2024-07-04 16:11:02 +02:00
(() => {
2024-07-05 16:04:12 +02:00
// node_modules/uuid/dist/esm-browser/stringify.js
2024-07-05 00:07:39 +02:00
var byteToHex = [];
for ( i = 0 ; i < 256 ; ++ i ) {
byteToHex . push (( i + 256 ). toString ( 16 ). slice ( 1 ));
}
var i ;
function unsafeStringify ( arr , offset = 0 ) {
return ( byteToHex [ arr [ offset + 0 ]] + byteToHex [ arr [ offset + 1 ]] + byteToHex [ arr [ offset + 2 ]] + byteToHex [ arr [ offset + 3 ]] + "-" + byteToHex [ arr [ offset + 4 ]] + byteToHex [ arr [ offset + 5 ]] + "-" + byteToHex [ arr [ offset + 6 ]] + byteToHex [ arr [ offset + 7 ]] + "-" + byteToHex [ arr [ offset + 8 ]] + byteToHex [ arr [ offset + 9 ]] + "-" + byteToHex [ arr [ offset + 10 ]] + byteToHex [ arr [ offset + 11 ]] + byteToHex [ arr [ offset + 12 ]] + byteToHex [ arr [ offset + 13 ]] + byteToHex [ arr [ offset + 14 ]] + byteToHex [ arr [ offset + 15 ]]). toLowerCase ();
}
2024-07-05 16:04:12 +02:00
// node_modules/uuid/dist/esm-browser/rng.js
2024-07-05 00:07:39 +02:00
var getRandomValues ;
var rnds8 = new Uint8Array ( 16 );
function rng () {
if ( ! getRandomValues ) {
getRandomValues = typeof crypto !== "undefined" && crypto . getRandomValues && crypto . getRandomValues . bind ( crypto );
if ( ! getRandomValues ) {
throw new Error ( "crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported" );
}
}
return getRandomValues ( rnds8 );
}
2024-07-05 16:04:12 +02:00
// node_modules/uuid/dist/esm-browser/native.js
2024-07-05 00:07:39 +02:00
var randomUUID = typeof crypto !== "undefined" && crypto . randomUUID && crypto . randomUUID . bind ( crypto );
var native_default = {
randomUUID
};
2024-07-05 16:04:12 +02:00
// node_modules/uuid/dist/esm-browser/v4.js
2024-07-05 00:07:39 +02:00
function v4 ( options , buf , offset ) {
if ( native_default . randomUUID && ! buf && ! options ) {
return native_default . randomUUID ();
}
options = options || {};
var rnds = options . random || ( options . rng || rng )();
rnds [ 6 ] = rnds [ 6 ] & 15 | 64 ;
rnds [ 8 ] = rnds [ 8 ] & 63 | 128 ;
if ( buf ) {
offset = offset || 0 ;
for ( var i = 0 ; i < 16 ; ++ i ) {
buf [ offset + i ] = rnds [ i ];
}
return buf ;
}
return unsafeStringify ( rnds );
}
var v4_default = v4 ;
2024-07-05 16:04:12 +02:00
// node_modules/bloatless-react/index.ts
2024-07-08 13:24:21 +02:00
function UUID () {
return v4_default ();
}
2024-07-04 17:27:46 +02:00
var State = class {
_value ;
_bindings = /* @__PURE__ */ new Set ();
2024-07-08 13:24:21 +02:00
// init
2024-07-04 17:27:46 +02:00
constructor ( initialValue ) {
this . _value = initialValue ;
}
2024-07-08 13:24:21 +02:00
// value
2024-07-04 17:27:46 +02:00
get value () {
return this . _value ;
}
set value ( newValue ) {
if ( this . _value == newValue ) return ;
this . _value = newValue ;
this . callSubscriptions ();
}
2024-07-08 13:24:21 +02:00
// subscriptions
2024-07-04 17:27:46 +02:00
callSubscriptions () {
this . _bindings . forEach (( fn ) => fn ( this . _value ));
}
subscribe ( fn ) {
this . _bindings . add ( fn );
fn ( this . _value );
}
2024-07-08 13:24:21 +02:00
// stringify
toString () {
return JSON . stringify ( this . _value );
}
2024-07-04 17:27:46 +02:00
};
2024-07-05 00:07:39 +02:00
var ListState = class extends State {
additionHandlers = /* @__PURE__ */ new Set ();
removalHandlers = /* @__PURE__ */ new Map ();
2024-07-08 13:24:21 +02:00
// init
constructor ( initialItems ) {
super ( new Set ( initialItems ));
2024-07-05 00:07:39 +02:00
}
2024-07-08 13:24:21 +02:00
// list
2024-07-05 00:07:39 +02:00
add (... items ) {
items . forEach (( item ) => {
this . value . add ( item );
this . additionHandlers . forEach (( handler ) => handler ( item ));
});
2024-07-08 13:24:21 +02:00
this . callSubscriptions ();
2024-07-05 00:07:39 +02:00
}
remove (... items ) {
items . forEach (( item ) => {
this . value . delete ( item );
2024-07-08 13:24:21 +02:00
const id = item . id ;
if ( ! this . removalHandlers . has ( id )) return ;
this . removalHandlers . get ( id )( item );
this . removalHandlers . delete ( id );
2024-07-05 00:07:39 +02:00
});
2024-07-08 13:24:21 +02:00
this . callSubscriptions ();
}
clear () {
this . remove (... this . value . values ());
2024-07-05 00:07:39 +02:00
}
2024-07-08 13:24:21 +02:00
// handlers
2024-07-05 00:07:39 +02:00
handleAddition ( handler ) {
this . additionHandlers . add ( handler );
2024-07-08 13:24:21 +02:00
[... this . value . values ()]. forEach ( handler );
2024-07-05 00:07:39 +02:00
}
handleRemoval ( item , handler ) {
2024-07-08 13:24:21 +02:00
this . removalHandlers . set ( item . id , handler );
}
// stringification
toString () {
const array = [... this . value ];
const json = JSON . stringify ( array );
return json ;
2024-07-05 00:07:39 +02:00
}
};
function createProxyState ( statesToSubscibe , fn ) {
const proxyState = new State ( fn ());
statesToSubscibe . forEach (
( state ) => state . subscribe (() => proxyState . value = fn ())
);
return proxyState ;
}
2024-07-04 16:11:02 +02:00
function createElement ( tagName , attributes = {}, ... children ) {
const element = document . createElement ( tagName );
if ( attributes != null )
Object . entries ( attributes ). forEach (( entry ) => {
const [ attributename , value ] = entry ;
const [ directiveKey , directiveValue ] = attributename . split ( ":" );
switch ( directiveKey ) {
case "on" : {
2024-07-05 00:07:39 +02:00
switch ( directiveValue ) {
case "enter" : {
element . addEventListener ( "keydown" , ( e ) => {
if ( e . key != "Enter" ) return ;
value ();
});
break ;
}
default : {
element . addEventListener ( directiveValue , value );
}
}
2024-07-04 16:11:02 +02:00
break ;
}
case "subscribe" : {
if ( directiveValue == "children" ) {
2024-07-08 13:24:21 +02:00
element . style . scrollBehavior = "smooth" ;
try {
const [ listState , toElement ] = value ;
listState . handleAddition (( newItem ) => {
const child = toElement ( newItem , listState );
listState . handleRemoval (
newItem ,
() => child . remove ()
);
element . append ( child );
child . scrollIntoView ();
});
} catch {
throw `error: cannot process subscribe:children directive because ListItemConverter is not defined. Usage: "subscribe:children={[list, converter]}"; you can find a more detailed example in the documentation` ;
}
2024-07-04 16:11:02 +02:00
} else {
const state = value ;
state . subscribe (
( newValue ) => element [ directiveValue ] = newValue
);
}
break ;
}
case "bind" : {
const state = value ;
state . subscribe (
( newValue ) => element [ directiveValue ] = newValue
);
element . addEventListener (
"input" ,
() => state . value = element [ directiveValue ]
);
break ;
}
case "toggle" : {
2024-07-08 13:24:21 +02:00
if ( value . subscribe ) {
const state = value ;
state . subscribe (
( newValue ) => element . toggleAttribute ( directiveValue , newValue )
);
} else {
element . toggleAttribute ( directiveValue , value );
}
break ;
}
case "set" : {
2024-07-04 16:11:02 +02:00
const state = value ;
state . subscribe (
2024-07-08 13:24:21 +02:00
( newValue ) => element . setAttribute ( directiveValue , newValue )
2024-07-04 16:11:02 +02:00
);
break ;
}
default :
element . setAttribute ( attributename , value );
}
});
children . filter (( x ) => x ). forEach (( child ) => element . append ( child ));
return element ;
}
2024-07-08 13:24:21 +02:00
// node_modules/udn-frontend/index.ts
2024-07-06 14:11:48 +02:00
var UDNFrontend = class {
ws ;
// handlers
connectionHandler = () => {
};
disconnectionHandler = () => {
};
messageHandler = ( data ) => {
};
// init
set onconnect ( handler ) {
this . connectionHandler = handler ;
}
set ondisconnect ( handler ) {
this . disconnectionHandler = handler ;
}
set onmessage ( handler ) {
this . messageHandler = 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
connect ( address ) {
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 );
this . messageHandler ( data );
});
}
sendMessage ( channel , body ) {
const messageObject = {
messageChannel : channel ,
messageBody : body
};
return this . send ( messageObject );
}
subscribe ( channel ) {
const messageObject = {
subscribeChannel : channel
};
return this . send ( messageObject );
}
unsubscribe ( channel ) {
const messageObject = {
unsubscribeChannel : channel
};
return this . send ( messageObject );
}
};
2024-07-05 00:07:39 +02:00
// src/translations.tsx
var staticTextEnglish = {
channel : "Channel" ,
channel_placeholder : "my-channel" ,
2024-07-07 14:02:01 +02:00
disconnected : "Server disconnected" ,
reconnecting : "Reconnecting..." ,
2024-07-05 16:49:08 +02:00
info : "Info" ,
2024-07-05 00:07:39 +02:00
message : "Message" ,
2024-07-05 16:04:12 +02:00
messages : "Messages" ,
2024-07-05 00:07:39 +02:00
message_placeholder : "Hello, world!" ,
message_placeholder_generic : "Type a message..." ,
noMessagesReceived : "No messages received" ,
messageLastReceived : "Last received message" ,
messagesReceived : "Received Messages" ,
send : "Send" ,
2024-07-05 16:49:08 +02:00
serverInfo : "Server Info" ,
2024-07-05 00:07:39 +02:00
settings : "Settings" ,
subscribeToChannel : "Subscribe to channel" ,
subscribe : "Subscribe" ,
unsubscribe : "Unubscribe"
};
var translations = {
en : staticTextEnglish ,
es : {
channel : "Canal" ,
channel_placeholder : "mi-canal" ,
2024-07-08 13:24:21 +02:00
disconnected : "Sin coneci\xF3n" ,
2024-07-07 14:02:01 +02:00
reconnecting : "Conectando..." ,
2024-07-05 16:49:08 +02:00
info : "Info" ,
2024-07-05 00:07:39 +02:00
message : "Mensaje" ,
2024-07-05 16:04:12 +02:00
messages : "Mensajes" ,
2024-07-05 00:07:39 +02:00
message_placeholder : "Hola!" ,
2024-07-05 16:04:12 +02:00
message_placeholder_generic : "Nuevo mensaje" ,
2024-07-05 00:07:39 +02:00
noMessagesReceived : "Sin mensajes" ,
2024-07-07 18:32:53 +02:00
messageLastReceived : "\xDAltimo mensaje" ,
2024-07-05 00:07:39 +02:00
messagesReceived : "Todos los Mensajes" ,
send : "Enviar" ,
2024-07-05 16:49:08 +02:00
serverInfo : "Informaci\xF3n" ,
2024-07-05 00:07:39 +02:00
settings : "Configuraci\xF3n" ,
subscribeToChannel : "Suscribirse a un canal" ,
subscribe : "Suscribirse" ,
unsubscribe : "Cancelar"
2024-07-05 16:04:12 +02:00
},
de : {
channel : "Kanal" ,
channel_placeholder : "mein-kanal" ,
2024-07-07 14:02:01 +02:00
disconnected : "Verbindung getrennt" ,
reconnecting : "Verbindung wird hergestellt..." ,
2024-07-05 16:49:08 +02:00
info : "Daten" ,
2024-07-05 16:04:12 +02:00
message : "Nachricht" ,
messages : "Nachrichten" ,
message_placeholder : "Hallo!" ,
message_placeholder_generic : "Neue Nachricht" ,
noMessagesReceived : "Keine Nachrichten" ,
2024-07-07 18:32:53 +02:00
messageLastReceived : "Letzte Nachricht" ,
2024-07-05 16:04:12 +02:00
messagesReceived : "Empfangene Nachrichten" ,
send : "Senden" ,
2024-07-05 16:49:08 +02:00
serverInfo : "Serverdaten" ,
2024-07-05 16:04:12 +02:00
settings : "Einstellungen" ,
2024-07-07 18:32:53 +02:00
subscribeToChannel : "Kanal beitreten" ,
subscribe : "Beitreten" ,
2024-07-05 16:04:12 +02:00
unsubscribe : "Verlassen"
2024-07-05 00:07:39 +02:00
}
};
function getText ( key ) {
2024-07-07 18:32:36 +02:00
const language = navigator . language . substring ( 0 , 2 );
if ( translations [ language ]) {
return translations [ language ][ key ];
2024-07-05 00:07:39 +02:00
}
return translations . en [ key ];
}
// src/model.tsx
var Message = class {
constructor ( channel , body ) {
this . channel = channel ;
this . body = body ;
}
uuid = new UUID ();
};
2024-07-06 14:11:48 +02:00
var UDN = new UDNFrontend ();
UDN . onconnect = () => {
2024-07-07 14:02:01 +02:00
isDisconnected . value = false ;
2024-07-06 14:11:48 +02:00
updateStats ();
};
UDN . onmessage = ( data ) => {
lastReceivedMessage . value = JSON . stringify ( data , null , 4 );
const { messageChannel , messageBody } = data ;
2024-07-05 16:04:12 +02:00
if ( messageChannel && messageBody ) {
const messageObject = new Message ( messageChannel , messageBody );
if ( messageBody ) messages . add ( messageObject );
2024-07-05 00:07:39 +02:00
}
2024-07-06 14:11:48 +02:00
};
2024-07-07 14:02:01 +02:00
UDN . ondisconnect = () => {
isDisconnected . value = true ;
setTimeout ( connect , 2e3 );
};
function connect () {
2024-07-08 02:00:39 +02:00
UDN . connect ( `wss:// ${ window . location . host } ` );
2024-07-07 14:02:01 +02:00
}
connect ();
var isDisconnected = new State ( true );
2024-07-05 00:07:39 +02:00
var messages = new ListState ();
var lastReceivedMessage = new State (
getText ( "noMessagesReceived" )
);
2024-07-05 16:49:08 +02:00
var statHTMLString = new State ( "" );
async function updateStats () {
const response = await fetch (
` ${ window . location . protocol } // ${ window . location . host } /stats`
);
const data = await response . json ();
let html = "" ;
data . forEach (( item ) => {
const tile = /* @__PURE__ */ createElement ( "div" , { class : "tile" }, /* @__PURE__ */ createElement ( "span" , { class : "secondary flex width-100" }, item [ 0 ]. toString ()), /* @__PURE__ */ createElement ( "b" , null , item [ 1 ]. toString ()));
html += tile . outerHTML ;
});
statHTMLString . value = html ;
}
2024-07-05 00:07:39 +02:00
var subscriptionChannel = new State ( "" );
var newMessageChannel = new State ( "" );
var newMessageBody = new State ( "" );
var isMessageEmpty = createProxyState (
[ newMessageChannel , newMessageBody ],
() => newMessageChannel . value == "" || newMessageBody . value == ""
);
2024-07-04 17:27:46 +02:00
function subscribe () {
2024-07-06 14:11:48 +02:00
UDN . subscribe ( subscriptionChannel . value );
2024-07-04 17:27:46 +02:00
}
function unsubscribe () {
2024-07-06 14:11:48 +02:00
UDN . unsubscribe ( subscriptionChannel . value );
2024-07-04 17:27:46 +02:00
}
function sendMessage () {
2024-07-05 16:49:08 +02:00
if ( isMessageEmpty . value == true ) return ;
2024-07-06 14:11:48 +02:00
UDN . sendMessage ( newMessageChannel . value , newMessageBody . value );
2024-07-05 00:07:39 +02:00
newMessageBody . value = "" ;
}
2024-07-05 16:49:08 +02:00
// src/infoScreen.tsx
function InfoScreen () {
return /* @__PURE__ */ createElement ( "article" , { id : "info-screen" }, /* @__PURE__ */ createElement ( "header" , null , getText ( "serverInfo" ), /* @__PURE__ */ createElement ( "span" , null , /* @__PURE__ */ createElement ( "button" , { "on:click" : updateStats }, /* @__PURE__ */ createElement ( "span" , { class : "icon" }, "refresh" )))), /* @__PURE__ */ createElement ( "div" , null , /* @__PURE__ */ createElement ( "div" , { class : "flex-column gap" , "subscribe:innerHTML" : statHTMLString })));
}
2024-07-05 00:07:39 +02:00
// src/mainScreen.tsx
function MainScreen () {
return /* @__PURE__ */ createElement ( "article" , { id : "main-screen" }, /* @__PURE__ */ createElement ( "header" , null , getText ( "settings" )), /* @__PURE__ */ createElement ( "div" , null , /* @__PURE__ */ createElement ( "div" , { class : "tile width-input" }, /* @__PURE__ */ createElement ( "div" , null , /* @__PURE__ */ createElement ( "b" , null , getText ( "messageLastReceived" )), /* @__PURE__ */ createElement ( "p" , { class : "secondary" , "subscribe:innerText" : lastReceivedMessage }))), /* @__PURE__ */ createElement ( "hr" , null ), /* @__PURE__ */ createElement ( "label" , { class : "tile" }, /* @__PURE__ */ createElement ( "div" , null , /* @__PURE__ */ createElement ( "span" , null , getText ( "subscribeToChannel" )), /* @__PURE__ */ createElement (
"input" ,
{
placeholder : getText ( "channel_placeholder" ),
"bind:value" : subscriptionChannel ,
"on:enter" : subscribe
}
))), /* @__PURE__ */ createElement ( "div" , { class : "flex-row width-input justify-end" }, /* @__PURE__ */ createElement ( "button" , { class : "danger width-50" , "on:click" : unsubscribe }, getText ( "unsubscribe" )), /* @__PURE__ */ createElement ( "button" , { class : "primary width-50" , "on:click" : subscribe }, getText ( "subscribe" ), /* @__PURE__ */ createElement ( "span" , { class : "icon" }, "arrow_forward" ))), /* @__PURE__ */ createElement ( "hr" , null ), /* @__PURE__ */ createElement ( "label" , { class : "tile" }, /* @__PURE__ */ createElement ( "div" , null , /* @__PURE__ */ createElement ( "span" , null , getText ( "channel" )), /* @__PURE__ */ createElement (
"input" ,
{
placeholder : getText ( "channel_placeholder" ),
"bind:value" : newMessageChannel ,
"on:enter" : sendMessage
}
))), /* @__PURE__ */ createElement ( "label" , { class : "tile" }, /* @__PURE__ */ createElement ( "div" , null , /* @__PURE__ */ createElement ( "span" , null , getText ( "message" )), /* @__PURE__ */ createElement (
"input" ,
{
placeholder : getText ( "message_placeholder" ),
"bind:value" : newMessageBody ,
"on:enter" : sendMessage
}
))), /* @__PURE__ */ createElement ( "div" , { class : "flex-row width-input justify-end" }, /* @__PURE__ */ createElement (
"button" ,
{
class : "primary width-50" ,
"on:click" : sendMessage ,
"toggle:disabled" : isMessageEmpty
},
getText ( "send" ),
2024-07-08 13:24:21 +02:00
/* @__PURE__ */ createElement ( "span" , { class : "icon" }, "send" )
2024-07-05 00:07:39 +02:00
))));
2024-07-04 17:27:46 +02:00
}
2024-07-05 00:07:39 +02:00
// src/messageScreen.tsx
var convertMessageToElement = ( message ) => {
return /* @__PURE__ */ createElement ( "div" , { class : "tile" , style : "flex: 0" }, /* @__PURE__ */ createElement ( "div" , null , /* @__PURE__ */ createElement ( "span" , { class : "secondary" }, message . channel ), /* @__PURE__ */ createElement ( "b" , null , message . body )));
};
function MessageScreen () {
return /* @__PURE__ */ createElement ( "article" , { id : "message-screen" }, /* @__PURE__ */ createElement ( "header" , null , getText ( "messagesReceived" )), /* @__PURE__ */ createElement ( "div" , null , /* @__PURE__ */ createElement (
"div" ,
{
class : "flex-column gap" ,
"subscribe:children" : [ messages , convertMessageToElement ]
}
)), /* @__PURE__ */ createElement ( "footer" , null , /* @__PURE__ */ createElement (
2024-07-04 17:27:46 +02:00
"input" ,
{
2024-07-05 00:07:39 +02:00
style : "max-width: unset" ,
placeholder : getText ( "message_placeholder_generic" ),
"bind:value" : newMessageBody ,
"on:enter" : sendMessage
2024-07-04 17:27:46 +02:00
}
2024-07-05 00:07:39 +02:00
), /* @__PURE__ */ createElement (
"button" ,
{
class : "primary" ,
"on:click" : sendMessage ,
"toggle:disabled" : isMessageEmpty
},
/* @__PURE__ */ createElement ( "span" , { class : "icon" }, "send" )
)));
}
// src/index.tsx
document . body . prepend (
2024-07-05 16:49:08 +02:00
/* @__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" )))
2024-07-04 17:27:46 +02:00
);
2024-07-05 16:49:08 +02:00
document . querySelector ( "main" ). append ( InfoScreen (), MainScreen (), MessageScreen ());
2024-07-07 14:02:01 +02:00
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" ))))))
);
2024-07-04 16:11:02 +02:00
})();