summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2022-09-09 17:49:39 +0200
committermetamuffin <metamuffin@disroot.org>2022-09-09 17:49:39 +0200
commit3a657c2f6d4cc9f82c993a8d390c8a84ab38bcb4 (patch)
tree731c854754d1408d189552da79bd81d79d11183f
parentb0c6062607b037ba1a6e388e5c23746bdd8dbdcf (diff)
downloadkeks-meet-3a657c2f6d4cc9f82c993a8d390c8a84ab38bcb4.tar
keks-meet-3a657c2f6d4cc9f82c993a8d390c8a84ab38bcb4.tar.bz2
keks-meet-3a657c2f6d4cc9f82c993a8d390c8a84ab38bcb4.tar.zst
chat!
-rw-r--r--client-web/public/assets/style/chat.css29
-rw-r--r--client-web/public/assets/style/master.css72
-rw-r--r--client-web/public/assets/style/room.css36
-rw-r--r--client-web/source/chat.ts41
-rw-r--r--client-web/source/helper.ts18
-rw-r--r--client-web/source/index.ts16
-rw-r--r--client-web/source/logger.ts13
-rw-r--r--client-web/source/menu.ts24
-rw-r--r--client-web/source/room.ts2
-rw-r--r--client-web/source/user/local.ts4
-rw-r--r--common/packets.d.ts1
11 files changed, 196 insertions, 60 deletions
diff --git a/client-web/public/assets/style/chat.css b/client-web/public/assets/style/chat.css
new file mode 100644
index 0000000..12741e6
--- /dev/null
+++ b/client-web/public/assets/style/chat.css
@@ -0,0 +1,29 @@
+/* TODO all of these rules are totally stupid */
+.chat {
+ overflow: scroll;
+
+ background-color: var(--bg);
+ padding: 1em;
+ border-radius: 1em;
+}
+
+.chat .message {
+ margin: 0.2em;
+}
+.chat .author {
+ font-weight: bold;
+}
+.chat .content {
+ color: white;
+}
+.chat .messages {
+ height: calc(100% - 5em);
+ width: 100%;
+ overflow: scroll;
+}
+.chat .controls {
+ padding: 1em;
+}
+.chat input {
+ width: 100%;
+}
diff --git a/client-web/public/assets/style/master.css b/client-web/public/assets/style/master.css
index 3013fa7..d67be15 100644
--- a/client-web/public/assets/style/master.css
+++ b/client-web/public/assets/style/master.css
@@ -1,5 +1,7 @@
@import url("https://s.metamuffin.org/static/font-ubuntu/include.css");
@import url("./logger.css");
+@import url("./chat.css");
+@import url("./room.css");
* {
font-family: "Ubuntu", sans-serif;
@@ -12,10 +14,6 @@
:root {
--bg: #151315;
--bg-dark: #070707;
- --bg-light: #417143;
- --bg-lighter: #949494;
- --bg-disabled: #720000;
- --bg-enabled: #097200;
--ac: #5e3f84;
--ac-light: #7c43bd;
--ac-dark: #12005e;
@@ -23,6 +21,27 @@
body {
background-color: var(--bg-dark);
+ height: 100vh;
+ width: 100vw;
+ justify-content: left;
+}
+
+/* layout magic, dont touch */
+.room {
+ display: table-cell;
+ white-space: nowrap;
+}
+.room:nth-child(2) {
+ width: 64vw;
+}
+.room:nth-child(1) {
+ width: 100vw;
+}
+.chat {
+ display: table-cell;
+ width: 35vw;
+ height: calc(100vh - 3em);
+ white-space: nowrap;
}
h2 {
@@ -42,6 +61,10 @@ input[type="button"]:hover,
button:hover {
filter: brightness(130%);
}
+input[type="button"].active,
+button.active {
+ filter: hue-rotate(20deg);
+}
input[type="text"] {
background-color: var(--bg-dark);
border: 1px solid var(--ac-light);
@@ -59,37 +82,6 @@ input[type="text"] {
z-index: 100;
}
-.room {
- width: 100%;
- height: 100%;
-}
-
-.user {
- background-color: var(--bg);
- border: 0px soly transparent;
- border-radius: 5px;
- padding: 1em;
- vertical-align: baseline;
- min-width: 10em;
- margin: 0.5em;
-}
-
-.user .info .name {
- font-weight: 400;
-}
-.user.local .info .name {
- text-decoration: underline;
-}
-.user .info {
- margin-bottom: 1em;
-}
-
-.media {
- max-height: 30vh;
- border: 0px solid transparent;
- border-radius: 5px;
-}
-
.start-box {
position: absolute;
top: 50vh;
@@ -104,10 +96,16 @@ input[type="text"] {
font-size: 32px;
}
-.menu-overlay {
- position: absolute;
+.menu-br {
+ position: fixed;
bottom: 0px;
right: 0px;
display: block;
text-align: right;
}
+.menu-br .version {
+ font-size: medium;
+ font-weight: bold;
+ color: var(--ac-light);
+ padding: 0.5em;
+}
diff --git a/client-web/public/assets/style/room.css b/client-web/public/assets/style/room.css
new file mode 100644
index 0000000..1d3ca88
--- /dev/null
+++ b/client-web/public/assets/style/room.css
@@ -0,0 +1,36 @@
+.room {
+ overflow-y: scroll;
+}
+
+.user {
+ background-color: var(--bg);
+ border: 0px soly transparent;
+ border-radius: 5px;
+ padding: 1em;
+ vertical-align: baseline;
+ min-width: 10em;
+ margin: 0.5em;
+}
+
+.user .info .name {
+ font-weight: 400;
+}
+.user.local .info .name {
+ text-decoration: underline;
+}
+.user .info {
+ margin-bottom: 1em;
+}
+
+.media {
+ max-height: 30vh;
+ border: 0px solid transparent;
+ border-radius: 5px;
+}
+
+.local-controls {
+ display: inline;
+}
+.local-controls::before {
+ content: "|";
+}
diff --git a/client-web/source/chat.ts b/client-web/source/chat.ts
new file mode 100644
index 0000000..d1165ee
--- /dev/null
+++ b/client-web/source/chat.ts
@@ -0,0 +1,41 @@
+import { ediv, espan } from "./helper.ts";
+import { CHAT } from "./index.ts";
+import { Room } from "./room.ts";
+import { User } from "./user/mod.ts";
+
+export class Chat {
+ private _shown = false;
+
+ messages = ediv({ class: "messages" })
+ controls = ediv({ class: "controls" })
+
+ get shown() { return this._shown }
+ set shown(value: boolean) {
+ if (value && !this._shown) document.body.prepend(CHAT)
+ if (!value && this._shown) document.body.removeChild(CHAT)
+ this._shown = value
+ }
+
+ constructor(public room: Room) {
+ const send = document.createElement("input")
+ send.type = "text"
+ send.onkeydown = (ev) => {
+ if (ev.code == "Enter") {
+ room.local_user.chat(send.value)
+ this.send_message(room.local_user, send.value)
+ send.value = ""
+ }
+ }
+ this.controls.append(send)
+ this.messages.append(document.createElement("hr"))
+ CHAT.append(this.messages, this.controls)
+ }
+
+ send_message(sender: User, message: string) {
+ this.messages.append(ediv({ class: "message" },
+ espan(sender.display_name, { class: "author" }),
+ ": ",
+ espan(message, { class: "content" })
+ ))
+ }
+}
diff --git a/client-web/source/helper.ts b/client-web/source/helper.ts
index 4f97ebb..8dafd29 100644
--- a/client-web/source/helper.ts
+++ b/client-web/source/helper.ts
@@ -6,14 +6,24 @@ export function hex_id(len = 8): string {
}
const elem = (s: string) => document.createElement(s)
-const elem_with_content = (s: string) => (c: string) => {
+
+interface Opts { class?: string[] | string, id?: string }
+
+function apply_opts(e: HTMLElement, o: Opts | undefined) {
+ if (!o) return
+ if (o.id) e.id = o.id
+ if (typeof o?.class == "string") e.classList.add(o.class)
+ if (typeof o?.class == "object") e.classList.add(...o.class)
+}
+const elem_with_content = (s: string) => (c: string, opts?: Opts) => {
const e = elem(s)
+ apply_opts(e, opts)
e.textContent = c
return e
}
-const elem_with_children = (s: string) => (opts: { class?: string[] }, ...cs: (HTMLElement | string)[]) => {
+const elem_with_children = (s: string) => (opts?: Opts, ...cs: (HTMLElement | string)[]) => {
const e = elem(s)
- if (opts.class) e.classList.add(...opts.class)
+ apply_opts(e, opts)
for (const c of cs) {
e.append(c)
}
@@ -28,4 +38,6 @@ export const eh4 = elem_with_content("h4")
export const eh5 = elem_with_content("h5")
export const eh6 = elem_with_content("h6")
export const ediv = elem_with_children("div")
+export const espan = elem_with_content("span")
+export const elabel = elem_with_content("label")
diff --git a/client-web/source/index.ts b/client-web/source/index.ts
index a57cec3..e8bbc0b 100644
--- a/client-web/source/index.ts
+++ b/client-web/source/index.ts
@@ -2,13 +2,17 @@
import { ediv } from "./helper.ts";
import { log } from "./logger.ts"
-import { create_menu } from "./menu.ts";
+import { setup_menus } from "./menu.ts";
import { load_params, PREFS } from "./preferences.ts";
import { SignalingConnection } from "./protocol/mod.ts";
import { Room } from "./room.ts"
-export const BOTTOM_CONTAINER = ediv({ class: ["bottom-container"] })
-export const ROOM_CONTAINER = ediv({ class: ["room"] })
+export const VERSION = "0.1.8"
+export const BOTTOM_CONTAINER = ediv({ class: "bottom-container" })
+export const ROOM_CONTAINER = ediv({ class: "room" })
+export const MENU_BR = ediv({ class: "menu-br" })
+export const CHAT = ediv({ class: "chat" })
+export const LOGGER_CONTAINER = ediv({ class: "logger-container" })
export const RTC_CONFIG: RTCConfiguration = {
// google stun!?
@@ -36,7 +40,7 @@ export async function main() {
if (PREFS.warn_redirect) log({ scope: "crypto", warn: true }, "You were redirected from the old URL format. The server knows you room name now - e2ee is insecure!")
const conn = await (new SignalingConnection().connect(room_name))
- new Room(conn)
- create_menu()
- document.body.append(ROOM_CONTAINER, BOTTOM_CONTAINER)
+ const r = new Room(conn)
+ setup_menus(r)
+ document.body.append(ROOM_CONTAINER, BOTTOM_CONTAINER, MENU_BR, LOGGER_CONTAINER)
}
diff --git a/client-web/source/logger.ts b/client-web/source/logger.ts
index 935eb20..c44ea6b 100644
--- a/client-web/source/logger.ts
+++ b/client-web/source/logger.ts
@@ -1,5 +1,7 @@
/// <reference lib="dom" />
+import { LOGGER_CONTAINER } from "./index.ts";
+
const log_scope_color = {
"*": "#ff4a7c",
crypto: "#c14aff",
@@ -13,8 +15,6 @@ const log_scope_color = {
export type LogScope = keyof typeof log_scope_color
export interface LogDesc { scope: LogScope, error?: boolean, warn?: boolean }
-let logger_container: HTMLDivElement
-
export function log(k: LogScope | LogDesc, message: string, ...data: unknown[]) {
for (let i = 0; i < data.length; i++) {
@@ -27,14 +27,14 @@ export function log(k: LogScope | LogDesc, message: string, ...data: unknown[])
(d.error ? console.error : d.warn ? console.warn : console.log)(`%c[${d.scope}] ${message}`, `color:${log_scope_color[d.scope]}`, ...data);
- if (logger_container) {
+ if (LOGGER_CONTAINER) {
const e = document.createElement("p")
e.classList.add("logger-line")
if (d.error) e.classList.add("logger-error")
else if (d.warn) e.classList.add("logger-warn")
else e.style.color = log_scope_color[d.scope]
e.textContent = `[${d.scope}] ${message}`
- logger_container.append(e)
+ LOGGER_CONTAINER.append(e)
setTimeout(() => {
e.classList.add("logger-line-disappear")
setTimeout(() => {
@@ -45,11 +45,6 @@ export function log(k: LogScope | LogDesc, message: string, ...data: unknown[])
}
globalThis.addEventListener("load", () => {
- const d = document.createElement("div")
- d.classList.add("logger-container")
- document.body.append(d)
- logger_container = d
-
// clear the console every hour so logs dont accumulate
setInterval(() => console.clear(), 1000 * 60 * 60)
})
diff --git a/client-web/source/menu.ts b/client-web/source/menu.ts
index a3755c3..5abb8f0 100644
--- a/client-web/source/menu.ts
+++ b/client-web/source/menu.ts
@@ -1,10 +1,10 @@
/// <reference lib="dom" />
-export function create_menu() {
- const menu = document.createElement("div")
- menu.classList.add("menu-overlay")
- document.body.append(menu)
+import { ep } from "./helper.ts"
+import { BOTTOM_CONTAINER, MENU_BR, VERSION } from "./index.ts"
+import { Room } from "./room.ts"
+export function setup_menus(room: Room) {
const item = (name: string, cb: (() => void) | string) => {
const p = document.createElement("p")
const a = document.createElement("a")
@@ -17,9 +17,23 @@ export function create_menu() {
return p
}
- menu.append(
+ MENU_BR.append(
+ ep(`keks-meet ${VERSION}`, { class: "version" }),
item("Settings", () => alert("todo, refer to the url parameters in the docs for now")),
item("Licence", "/licence"),
item("Sources / Documentation", "https://codeberg.org/metamuffin/keks-meet"),
)
+
+
+ // TODO this should ideally be a checkbox
+ const chat_toggle = document.createElement("input")
+ chat_toggle.type = "button"
+ chat_toggle.id = "chat_toggle"
+ chat_toggle.value = "Toggle chat"
+ chat_toggle.onclick = () => {
+ room.chat.shown = !room.chat.shown
+ if (room.chat.shown) chat_toggle.classList.add("active")
+ else chat_toggle.classList.remove("active")
+ }
+ BOTTOM_CONTAINER.append(chat_toggle)
}
diff --git a/client-web/source/room.ts b/client-web/source/room.ts
index 5813faa..53c020f 100644
--- a/client-web/source/room.ts
+++ b/client-web/source/room.ts
@@ -6,12 +6,14 @@ import { User } from "./user/mod.ts";
import { LocalUser } from "./user/local.ts";
import { ClientboundPacket, RelayMessage } from "../../common/packets.d.ts";
import { SignalingConnection } from "./protocol/mod.ts";
+import { Chat } from "./chat.ts";
export class Room {
public users: Map<number, User> = new Map()
public remote_users: Map<number, RemoteUser> = new Map()
public local_user!: LocalUser
public my_id!: number
+ public chat: Chat = new Chat(this)
constructor(public signaling: SignalingConnection) {
this.signaling.control_handler = (a) => this.control_handler(a)
diff --git a/client-web/source/user/local.ts b/client-web/source/user/local.ts
index 2ea1ea6..053bc0a 100644
--- a/client-web/source/user/local.ts
+++ b/client-web/source/user/local.ts
@@ -46,6 +46,10 @@ export class LocalUser extends User {
})
}
+ chat(content: string) {
+ this.room.signaling.send_relay({ chat: { content } })
+ }
+
add_initial_to_remote(u: RemoteUser) {
this.tracks.forEach(t => u.peer.addTrack(t.track))
}
diff --git a/common/packets.d.ts b/common/packets.d.ts
index 3e5b612..058c248 100644
--- a/common/packets.d.ts
+++ b/common/packets.d.ts
@@ -17,6 +17,7 @@ export interface ServerboundPacket {
}
export interface RelayMessage {
+ chat?: { content: string },
identify?: { username: string }
offer?: F_RTCSessionDescriptionInit,
answer?: F_RTCSessionDescriptionInit,