handle disconnection on frontend

This commit is contained in:
marlon-erler
2024-07-07 14:02:01 +02:00
parent 9ef5c2f0a2
commit e010de6a30
10 changed files with 70 additions and 9 deletions
+5 -4
View File
@@ -73,10 +73,11 @@ For TypeScript-based apps, you can use the [udn-frontend](https://github.com/mar
The web interface of the server itself is based on my other two projects, [carbon-mini](https://github.com/marlon-erler/carbon-mini) and [bloatless-react](https://github.com/marlon-erler/bloatless-react). The web interface of the server itself is based on my other two projects, [carbon-mini](https://github.com/marlon-erler/carbon-mini) and [bloatless-react](https://github.com/marlon-erler/bloatless-react).
Both of these projects are very minimal, bloat-free, and quick to get started with. I'd suggest you to build your app based on the same foundation for a consistent user experience. Both of these projects are very minimal, bloat-free, and quick to get started with. I'd suggest you to build your app based on the same foundation for a consistent user experience.
1. Download [carbon-mini](https://github.com/marlon-erler/carbon-mini) from the releases page 1. Download [carbon-mini](https://github.com/marlon-erler/carbon-mini) from the releases page and read the docs
2. Install [bloatless-react](https://github.com/marlon-erler/bloatless-react) 2. Install [bloatless-react](https://github.com/marlon-erler/bloatless-react) and read the docs
3. Install [udn-frontend](https://github.com/marlon-erler/udn-frontend) 3. Install [udn-frontend](https://github.com/marlon-erler/udn-frontend) and read the docs
4. Start developing 4. Generate your app icon [here](https://icongen.onrender.com/), move it to the `dist` directory
5. Start developing
## Manual way ## Manual way
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 33 KiB

+2 -1
View File
@@ -1,6 +1,6 @@
<html lang="en"> <html lang="en">
<head> <head>
<title>UDN Server</title> <title>My App</title>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta <meta
@@ -21,6 +21,7 @@
<link rel="stylesheet" href="styles.css" /> <link rel="stylesheet" href="styles.css" />
<link rel="manifest" href="manifest.json" /> <link rel="manifest" href="manifest.json" />
<link rel="icon" href="icon.png" />
<script src="support.js" defer></script> <script src="support.js" defer></script>
<script src="index.js" defer></script> <script src="index.js" defer></script>
+18
View File
@@ -245,6 +245,8 @@
var staticTextEnglish = { var staticTextEnglish = {
channel: "Channel", channel: "Channel",
channel_placeholder: "my-channel", channel_placeholder: "my-channel",
disconnected: "Server disconnected",
reconnecting: "Reconnecting...",
info: "Info", info: "Info",
message: "Message", message: "Message",
messages: "Messages", messages: "Messages",
@@ -265,6 +267,8 @@
es: { es: {
channel: "Canal", channel: "Canal",
channel_placeholder: "mi-canal", channel_placeholder: "mi-canal",
disconnected: "Sin conneci\xF3n",
reconnecting: "Conectando...",
info: "Info", info: "Info",
message: "Mensaje", message: "Mensaje",
messages: "Mensajes", messages: "Mensajes",
@@ -283,6 +287,8 @@
de: { de: {
channel: "Kanal", channel: "Kanal",
channel_placeholder: "mein-kanal", channel_placeholder: "mein-kanal",
disconnected: "Verbindung getrennt",
reconnecting: "Verbindung wird hergestellt...",
info: "Daten", info: "Daten",
message: "Nachricht", message: "Nachricht",
messages: "Nachrichten", messages: "Nachrichten",
@@ -316,6 +322,7 @@
}; };
var UDN = new UDNFrontend(); var UDN = new UDNFrontend();
UDN.onconnect = () => { UDN.onconnect = () => {
isDisconnected.value = false;
updateStats(); updateStats();
}; };
UDN.onmessage = (data) => { UDN.onmessage = (data) => {
@@ -326,7 +333,15 @@
if (messageBody) messages.add(messageObject); if (messageBody) messages.add(messageObject);
} }
}; };
UDN.ondisconnect = () => {
isDisconnected.value = true;
setTimeout(connect, 2e3);
};
function connect() {
UDN.connect(`ws://${window.location.host}`); UDN.connect(`ws://${window.location.host}`);
}
connect();
var isDisconnected = new State(true);
var messages = new ListState(); var messages = new ListState();
var lastReceivedMessage = new State( var lastReceivedMessage = new State(
getText("noMessagesReceived") getText("noMessagesReceived")
@@ -438,4 +453,7 @@
/* @__PURE__ */ createElement("menu", null, /* @__PURE__ */ createElement("a", { class: "tab-link", href: "#info-screen", active: true }, /* @__PURE__ */ createElement("span", { class: "icon" }, "info"), getText("info")), /* @__PURE__ */ createElement("a", { class: "tab-link", href: "#main-screen" }, /* @__PURE__ */ createElement("span", { class: "icon" }, "settings"), getText("settings")), /* @__PURE__ */ createElement("a", { class: "tab-link", href: "#message-screen" }, /* @__PURE__ */ createElement("span", { class: "icon" }, "chat"), getText("messages"))) /* @__PURE__ */ createElement("menu", null, /* @__PURE__ */ createElement("a", { class: "tab-link", href: "#info-screen", active: true }, /* @__PURE__ */ createElement("span", { class: "icon" }, "info"), getText("info")), /* @__PURE__ */ createElement("a", { class: "tab-link", href: "#main-screen" }, /* @__PURE__ */ createElement("span", { class: "icon" }, "settings"), getText("settings")), /* @__PURE__ */ createElement("a", { class: "tab-link", href: "#message-screen" }, /* @__PURE__ */ createElement("span", { class: "icon" }, "chat"), getText("messages")))
); );
document.querySelector("main").append(InfoScreen(), MainScreen(), MessageScreen()); document.querySelector("main").append(InfoScreen(), MainScreen(), MessageScreen());
document.body.append(
/* @__PURE__ */ createElement("div", { class: "modal", "toggle:open": isDisconnected }, /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("main", null, /* @__PURE__ */ createElement("div", { class: "flex-column align-center justify-center width-100 height-100", style: "gap: 1rem" }, /* @__PURE__ */ createElement("span", { class: "icon error", style: "font-size: 3rem" }, "signal_disconnected"), /* @__PURE__ */ createElement("h1", { class: "error" }, getText("disconnected")), /* @__PURE__ */ createElement("p", { class: "secondary" }, getText("reconnecting"))))))
);
})(); })();
+1 -1
View File
@@ -3,7 +3,7 @@
"display": "standalone", "display": "standalone",
"icons": [ "icons": [
{ {
"src": "favicon.ico", "src": "icon.png",
"sizes": "any" "sizes": "any"
} }
] ]
+8 -1
View File
@@ -279,6 +279,7 @@ select {
header, header,
menu { menu {
backdrop-filter: blur(70px); backdrop-filter: blur(70px);
-webkit-backdrop-filter: blur(70px);
} }
/* border, outline, etc */ /* border, outline, etc */
@@ -604,6 +605,7 @@ select + .icon,
article, article,
main, main,
select + .icon, select + .icon,
.height-100,
.modal > div, .modal > div,
.modal main { .modal main {
height: 100%; height: 100%;
@@ -757,12 +759,17 @@ body {
height: 100%; height: 100%;
} }
body { body,
.modal {
padding-left: var(--safe-area-left); padding-left: var(--safe-area-left);
padding-right: var(--safe-area-right); padding-right: var(--safe-area-right);
padding-top: var(--safe-area-top); padding-top: var(--safe-area-top);
} }
.modal {
padding-bottom: var(--safe-area-bottom);
}
menu { menu {
width: 100%; width: 100%;
height: var(--menu-height-mobile); height: var(--menu-height-mobile);
+16
View File
@@ -4,6 +4,7 @@ import { InfoScreen } from "./infoScreen";
import { MainScreen } from "./mainScreen"; import { MainScreen } from "./mainScreen";
import { MessageScreen } from "./messageScreen"; import { MessageScreen } from "./messageScreen";
import { getText } from "./translations"; import { getText } from "./translations";
import { isDisconnected } from "./model";
// WS // WS
document.body.prepend( document.body.prepend(
@@ -25,3 +26,18 @@ document.body.prepend(
document document
.querySelector("main")! .querySelector("main")!
.append(InfoScreen(), MainScreen(), MessageScreen()); .append(InfoScreen(), MainScreen(), MessageScreen());
document.body.append(
<div class="modal" toggle:open={isDisconnected}>
<div>
<main>
<div class="flex-column align-center justify-center width-100 height-100" style="gap: 1rem">
<span class="icon error" style="font-size: 3rem">
signal_disconnected
</span>
<h1 class="error">{getText("disconnected")}</h1>
<p class="secondary">{getText("reconnecting")}</p>
</div>
</main>
</div>
</div>
);
+13 -1
View File
@@ -13,6 +13,7 @@ export class Message implements React.Identifiable {
const UDN = new UDNFrontend(); const UDN = new UDNFrontend();
UDN.onconnect = () => { UDN.onconnect = () => {
isDisconnected.value = false;
updateStats(); updateStats();
}; };
@@ -26,9 +27,20 @@ UDN.onmessage = (data) => {
} }
}; };
UDN.connect(`ws://${window.location.host}`) UDN.ondisconnect = () => {
isDisconnected.value = true;
setTimeout(connect, 2000);
};
function connect() {
UDN.connect(`ws://${window.location.host}`);
}
connect();
// STATE // STATE
// connection
export const isDisconnected = new React.State(true);
// messages // messages
export const messages = new React.ListState<Message>(); export const messages = new React.ListState<Message>();
export const lastReceivedMessage = new React.State( export const lastReceivedMessage = new React.State(
+6
View File
@@ -2,6 +2,8 @@
export const staticTextEnglish = { export const staticTextEnglish = {
channel: "Channel", channel: "Channel",
channel_placeholder: "my-channel", channel_placeholder: "my-channel",
disconnected: "Server disconnected",
reconnecting: "Reconnecting...",
info: "Info", info: "Info",
message: "Message", message: "Message",
messages: "Messages", messages: "Messages",
@@ -23,6 +25,8 @@ export const translations: { [key: string]: typeof staticTextEnglish } = {
es: { es: {
channel: "Canal", channel: "Canal",
channel_placeholder: "mi-canal", channel_placeholder: "mi-canal",
disconnected: "Sin conneción",
reconnecting: "Conectando...",
info: "Info", info: "Info",
message: "Mensaje", message: "Mensaje",
messages: "Mensajes", messages: "Mensajes",
@@ -41,6 +45,8 @@ export const translations: { [key: string]: typeof staticTextEnglish } = {
de: { de: {
channel: "Kanal", channel: "Kanal",
channel_placeholder: "mein-kanal", channel_placeholder: "mein-kanal",
disconnected: "Verbindung getrennt",
reconnecting: "Verbindung wird hergestellt...",
info: "Daten", info: "Daten",
message: "Nachricht", message: "Nachricht",
messages: "Nachrichten", messages: "Nachrichten",