2024-07-07 13:43:18 +02:00
(() => {
2024-07-20 05:10:50 +02:00
// node_modules/uuid/dist/esm-browser/stringify.js
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 ();
}
// node_modules/uuid/dist/esm-browser/rng.js
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 );
}
// node_modules/uuid/dist/esm-browser/native.js
var randomUUID = typeof crypto !== "undefined" && crypto . randomUUID && crypto . randomUUID . bind ( crypto );
var native_default = {
randomUUID
};
// node_modules/uuid/dist/esm-browser/v4.js
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-20 02:18:15 +02:00
// node_modules/bloatless-react/index.ts
var State = class {
_value ;
_bindings = /* @__PURE__ */ new Set ();
// init
constructor ( initialValue ) {
this . _value = initialValue ;
}
// value
get value () {
return this . _value ;
}
set value ( newValue ) {
if ( this . _value == newValue ) return ;
this . _value = newValue ;
this . callSubscriptions ();
}
// subscriptions
callSubscriptions () {
this . _bindings . forEach (( fn ) => fn ( this . _value ));
}
subscribe ( fn ) {
this . _bindings . add ( fn );
fn ( this . _value );
}
subscribeSilent ( fn ) {
this . _bindings . add ( fn );
}
// stringify
toString () {
return JSON . stringify ( this . _value );
}
};
2024-07-20 02:56:44 +02:00
var ListState = class extends State {
additionHandlers = /* @__PURE__ */ new Set ();
removalHandlers = /* @__PURE__ */ new Map ();
// init
constructor ( initialItems ) {
super ( new Set ( initialItems ));
}
// list
add (... items ) {
items . forEach (( item ) => {
this . value . add ( item );
this . additionHandlers . forEach (( handler ) => handler ( item ));
});
this . callSubscriptions ();
}
remove (... items ) {
items . forEach (( item ) => {
this . value . delete ( item );
if ( ! this . removalHandlers . has ( item )) return ;
this . removalHandlers . get ( item ). forEach (( handler ) => handler ( item ));
this . removalHandlers . delete ( item );
});
this . callSubscriptions ();
}
clear () {
this . remove (... this . value . values ());
}
// handlers
handleAddition ( handler ) {
this . additionHandlers . add ( handler );
[... this . value . values ()]. forEach ( handler );
}
handleRemoval ( item , handler ) {
if ( ! this . removalHandlers . has ( item ))
this . removalHandlers . set ( item , /* @__PURE__ */ new Set ());
this . removalHandlers . get ( item ). add ( handler );
}
// stringification
toString () {
const array = [... this . value . values ()];
const json = JSON . stringify ( array );
return json ;
}
};
2024-07-20 02:18:15 +02:00
function createProxyState ( statesToSubscibe , fn ) {
const proxyState = new State ( fn ());
statesToSubscibe . forEach (
( state ) => state . subscribe (() => proxyState . value = fn ())
);
return proxyState ;
}
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" : {
switch ( directiveValue ) {
case "enter" : {
element . addEventListener ( "keydown" , ( e ) => {
if ( e . key != "Enter" ) return ;
value ();
});
break ;
}
default : {
element . addEventListener ( directiveValue , value );
}
}
break ;
}
case "subscribe" : {
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" : {
if ( value . subscribe ) {
const state = value ;
state . subscribe (
( newValue ) => element . toggleAttribute ( directiveValue , newValue )
);
} else {
element . toggleAttribute ( directiveValue , value );
}
break ;
}
case "set" : {
const state = value ;
state . subscribe (
( newValue ) => element . setAttribute ( directiveValue , newValue )
);
break ;
}
case "children" : {
switch ( directiveValue ) {
case "set" : {
const state = value ;
state . subscribe (( newValue ) => {
element . innerHTML = "" ;
element . append (...[ newValue ]. flat ());
});
break ;
}
case "append" :
case "appendandscroll" :
case "prepend" : {
element . style . scrollBehavior = "smooth" ;
try {
const [ listState , toElement ] = value ;
listState . handleAddition (( newItem ) => {
const child = toElement ( newItem );
listState . handleRemoval (
newItem ,
() => child . remove ()
);
if ( directiveValue == "append" ) {
element . append ( child );
} else if ( directiveValue == "prepend" ) {
element . prepend ( child );
}
});
} catch {
throw `error: cannot process subscribe:children directive because StateItemConverter is not defined. Usage: "subscribe:children={[list, converter]}"; you can find a more detailed example in the documentation` ;
}
}
}
}
default :
element . setAttribute ( attributename , value );
}
});
children . filter (( x ) => x ). forEach (( child ) => element . append ( child ));
return element ;
}
2024-07-20 05:10:50 +02:00
// src/Model/Utility/utility.ts
2024-07-20 21:10:06 +02:00
function createTimestamp () {
return ( /* @__PURE__ */ new Date ()). toISOString ();
}
2024-07-20 05:10:50 +02:00
function stringify ( data ) {
2024-07-20 20:42:43 +02:00
return JSON . stringify ( data , null , 4 );
2024-07-20 05:10:50 +02:00
}
function parse ( string ) {
return JSON . parse ( string );
}
2024-07-20 18:58:25 +02:00
function localeCompare ( a , b ) {
return a . localeCompare ( b );
}
2024-07-20 05:10:50 +02:00
// src/Model/Utility/typeSafety.ts
var DATA_VERSION = "v2" ;
function checkIsValidObject ( object ) {
return object . dataVersion == DATA_VERSION ;
}
// src/Model/storageModel.ts
var PATH_COMPONENT_SEPARATOR = "\\" ;
var StorageModel = class _StorageModel {
storageEntryTree = {};
// basic
store = ( pathComponents , value ) => {
const key = _StorageModel . pathComponentsToKey (... pathComponents );
localStorage . setItem ( key , value );
this . updateTree (... pathComponents );
};
restore = ( pathComponents ) => {
const key = _StorageModel . pathComponentsToKey (... pathComponents );
return localStorage . getItem ( key );
};
remove = ( pathComponents , shouldInitialize = true ) => {
const key = _StorageModel . pathComponentsToKey (... pathComponents );
localStorage . removeItem ( key );
if ( shouldInitialize == true ) {
this . initializeTree ();
}
};
removeRecursive = ( pathComponentsOfEntityToDelete ) => {
a : for ( const key of Object . keys ( localStorage )) {
const pathComponentsOfCurrentEntity = _StorageModel . keyToPathComponents ( key );
for ( let i = 0 ; i < pathComponentsOfEntityToDelete . length ; i ++ ) {
if ( ! pathComponentsOfCurrentEntity [ i ]) continue a ;
if ( pathComponentsOfCurrentEntity [ i ] != pathComponentsOfEntityToDelete [ i ])
continue a ;
}
this . remove ( pathComponentsOfCurrentEntity , false );
}
this . initializeTree ();
};
list = ( pathComponents ) => {
let currentParent = this . storageEntryTree ;
for ( const component of pathComponents ) {
const nextParent = currentParent [ component ];
if ( nextParent == void 0 ) return [];
currentParent = nextParent ;
}
return [... Object . keys ( currentParent )];
};
// stringifiable
storeStringifiable = ( pathComponents , value ) => {
const valueString = stringify ( value );
this . store ( pathComponents , valueString );
};
restoreStringifiable = ( pathComponents ) => {
const valueString = this . restore ( pathComponents );
if ( ! valueString ) return null ;
return parse ( valueString );
};
// init
constructor () {
this . initializeTree ();
}
// utility
initializeTree = () => {
console . log ( "initializing tree" );
this . storageEntryTree = {};
for ( const key of Object . keys ( localStorage )) {
const components = _StorageModel . keyToPathComponents ( key );
this . updateTree (... components );
}
};
updateTree = (... pathComponents ) => {
let currentParent = this . storageEntryTree ;
for ( const pathPart of pathComponents ) {
if ( ! currentParent [ pathPart ]) {
currentParent [ pathPart ] = {};
}
currentParent = currentParent [ pathPart ];
}
};
print = () => {
2024-07-20 20:42:43 +02:00
console . log ( stringify ( this . storageEntryTree ));
2024-07-20 05:10:50 +02:00
};
static pathComponentsToKey = (... pathComponents ) => {
return pathComponents . join ( PATH_COMPONENT_SEPARATOR );
};
static keyToPathComponents = ( key ) => {
return key . split ( PATH_COMPONENT_SEPARATOR );
};
static join = (... items ) => {
let allComponents = [];
for ( const item of items ) {
const parts = this . keyToPathComponents ( item );
allComponents . push (... parts );
}
return _StorageModel . pathComponentsToKey (... allComponents );
};
};
var storageKeys = {
// connection
socketAddress : [ DATA_VERSION , "connection" , "socket-address" ],
2024-07-20 20:42:43 +02:00
outbox : [ DATA_VERSION , "connection" , "outbox" ],
2024-07-20 05:10:50 +02:00
// settings
username : [ DATA_VERSION , "settings" , "user-name" ],
firstDayOfWeek : [ DATA_VERSION , "settings" , "first-day-of-week" ],
// history
previousAddresses : [ DATA_VERSION , "history" , "previous-addresses" ],
previousObjectCategories : [ DATA_VERSION , "history" , "object-categories" ],
previousObjectStatuses : [ DATA_VERSION , "history" , "object-statuses" ],
previousObjectFilters : [ DATA_VERSION , "history" , "object-filters" ],
// chat etc
chats : [ DATA_VERSION , "chat" ],
chatInfo : ( id ) => [ DATA_VERSION , "chat" , id , "info" ],
2024-07-20 20:42:43 +02:00
chatLastUsedPage : ( id ) => [
DATA_VERSION ,
"chat" ,
id ,
"last-used-page"
],
2024-07-20 18:10:42 +02:00
chatColor : ( id ) => [ DATA_VERSION , "chat" , id , "color" ],
2024-07-20 05:10:50 +02:00
chatMessages : ( id ) => [ DATA_VERSION , "chat" , id , "messages" ],
2024-07-20 20:42:43 +02:00
chatObjects : ( id ) => [ DATA_VERSION , "chat" , id , "objects" ]
2024-07-20 05:10:50 +02:00
};
2024-07-20 18:10:42 +02:00
// src/ViewModel/colors.ts
var Color = /* @__PURE__ */ (( Color2 ) => {
Color2 [ "Standard" ] = "standard" ;
Color2 [ "Coral" ] = "coral" ;
Color2 [ "Yellow" ] = "yellow" ;
Color2 [ "Mint" ] = "mint" ;
Color2 [ "LightBlue" ] = "lightblue" ;
Color2 [ "Blue" ] = "blue" ;
Color2 [ "purple" ] = "purple" ;
return Color2 ;
})( Color || {});
2024-07-20 05:10:50 +02:00
// src/Model/chatModel.ts
2024-07-20 21:10:06 +02:00
var ChatModel = class _ChatModel {
2024-07-20 20:42:43 +02:00
connectionModel ;
2024-07-20 05:10:50 +02:00
storageModel ;
2024-07-20 20:42:43 +02:00
settingsModel ;
2024-07-20 14:16:26 +02:00
chatListModel ;
2024-07-20 20:42:43 +02:00
// data
id ;
2024-07-20 05:10:50 +02:00
info ;
2024-07-20 18:10:42 +02:00
color ;
2024-07-20 05:10:50 +02:00
messages = /* @__PURE__ */ new Set ();
objects = /* @__PURE__ */ new Map ();
2024-07-20 20:42:43 +02:00
// sorting
get index () {
return this . chatListModel . getIndexOfPrimaryChannel (
this . info . primaryChannel
);
}
2024-07-20 05:10:50 +02:00
// paths
get infoPath () {
return storageKeys . chatInfo ( this . id );
}
2024-07-20 18:10:42 +02:00
get colorPath () {
return storageKeys . chatColor ( this . id );
}
2024-07-20 05:10:50 +02:00
get messageDirPath () {
return storageKeys . chatMessages ( this . id );
}
get objectDirPath () {
return storageKeys . chatObjects ( this . id );
}
getMessagePath = ( id ) => {
return [... this . messageDirPath , id ];
};
getObjectPath = ( id ) => {
return [... this . objectDirPath , id ];
};
// set
setPrimaryChannel = ( primaryChannel ) => {
this . info . primaryChannel = primaryChannel ;
this . storeInfo ();
2024-07-20 17:30:36 +02:00
this . chatListModel . updateIndices ();
2024-07-20 05:10:50 +02:00
};
setSecondaryChannels = ( secondaryChannels ) => {
this . info . secondaryChannels = secondaryChannels ;
this . storeInfo ();
};
2024-07-20 19:18:19 +02:00
setEncryptionKey = ( key ) => {
this . info . encryptionKey = key ;
this . storeInfo ();
};
2024-07-20 18:10:42 +02:00
setColor = ( color ) => {
this . color = color ;
this . storeColor ();
};
2024-07-20 05:10:50 +02:00
// store & add
storeInfo = () => {
this . storageModel . storeStringifiable ( this . infoPath , this . info );
};
2024-07-20 18:10:42 +02:00
storeColor = () => {
this . storageModel . store ( this . colorPath , this . color );
};
2024-07-20 05:10:50 +02:00
addMessage = ( message ) => {
if ( ! this . messages . has ( message )) {
this . messages . add ( message );
}
const messagePath = this . getMessagePath ( message . id );
this . storageModel . storeStringifiable ( messagePath , message );
};
addObject = ( object ) => {
this . objects . set ( object . id , object );
const objectPath = this . getObjectPath ( object . id );
this . storageModel . storeStringifiable ( objectPath , object );
};
2024-07-20 14:16:26 +02:00
// delete
delete = () => {
2024-07-20 05:10:50 +02:00
this . unloadData ();
2024-07-20 14:16:26 +02:00
this . chatListModel . untrackChat ( this );
2024-07-20 05:10:50 +02:00
const dirPath = [... storageKeys . chats , this . id ];
this . storageModel . removeRecursive ( dirPath );
};
// restore
restoreInfo = () => {
const info = this . storageModel . restoreStringifiable ( this . infoPath );
if ( info != null ) {
this . info = info ;
} else {
2024-07-20 21:10:06 +02:00
this . info = _ChatModel . generateChatInfo ( "0" );
2024-07-20 05:10:50 +02:00
}
};
2024-07-20 18:10:42 +02:00
restoreColor = () => {
const path = this . colorPath ;
const color = this . storageModel . restore ( path );
if ( ! color ) {
this . color = "standard" /* Standard */ ;
} else {
this . color = color ;
}
};
2024-07-20 05:10:50 +02:00
restoreMessages = () => {
const messageIds = this . storageModel . list ( this . messageDirPath );
if ( ! Array . isArray ( messageIds )) return ;
for ( const messageId of messageIds ) {
const messagePath = this . getMessagePath ( messageId );
const message = this . storageModel . restoreStringifiable ( messagePath );
if ( checkIsValidObject ( message ) == false ) return ;
this . messages . add ( message );
}
};
restoreObjects = () => {
const objectIds = this . storageModel . list ( this . objectDirPath );
if ( ! Array . isArray ( objectIds )) return ;
for ( const objectId of objectIds ) {
const objectPathComponents = this . getObjectPath ( objectId );
const object = this . storageModel . restoreStringifiable ( objectPathComponents );
if ( checkIsValidObject ( object ) == false ) return ;
if ( object . id != objectId ) return ;
this . objects . set ( objectId , object );
}
};
2024-07-20 20:42:43 +02:00
// messaging
sendMessage = ( body ) => {
2024-07-20 21:10:06 +02:00
const senderName = this . settingsModel . username ;
if ( senderName == "" ) return false ;
const allChannels = [ this . info . primaryChannel ];
for ( const secondaryChannel of this . info . secondaryChannels ) {
allChannels . push ( secondaryChannel );
}
const combinedChannel = allChannels . join ( "/" );
const chatMessage = _ChatModel . createChatMessage (
combinedChannel ,
senderName ,
body
);
this . connectionModel . sendMessageOrStore ( chatMessage );
return true ;
2024-07-20 20:42:43 +02:00
};
2024-07-20 05:10:50 +02:00
// memory
loadData = () => {
this . restoreMessages ();
this . restoreObjects ();
};
unloadData = () => {
this . messages . clear ();
this . objects . clear ();
};
// init
2024-07-20 20:42:43 +02:00
constructor ( storageModel2 , connectionModel2 , settingsModel2 , chatListModel2 , chatId ) {
2024-07-20 05:10:50 +02:00
this . id = chatId ;
2024-07-20 20:42:43 +02:00
this . connectionModel = connectionModel2 ;
this . settingsModel = settingsModel2 ;
2024-07-20 05:10:50 +02:00
this . storageModel = storageModel2 ;
2024-07-20 20:42:43 +02:00
this . chatListModel = chatListModel2 ;
2024-07-20 05:10:50 +02:00
this . restoreInfo ();
2024-07-20 18:10:42 +02:00
this . restoreColor ();
2024-07-20 05:10:50 +02:00
}
2024-07-20 21:10:06 +02:00
// utility
static generateChatInfo = ( primaryChannel ) => {
return {
primaryChannel ,
secondaryChannels : [],
encryptionKey : "" ,
hasUnreadMessages : false
};
2024-07-20 05:10:50 +02:00
};
2024-07-20 21:10:06 +02:00
static createChatMessage = ( channel , sender , body ) => {
return {
dataVersion : "v2" ,
id : v4_default (),
channel ,
sender ,
body ,
dateSent : createTimestamp ()
};
};
};
2024-07-20 05:10:50 +02:00
// src/Model/chatListModel.ts
var ChatListModel = class {
storageModel ;
2024-07-20 20:42:43 +02:00
settingsModel ;
connectionModel ;
2024-07-20 05:10:50 +02:00
// data
2024-07-20 16:49:01 +02:00
chatModels = /* @__PURE__ */ new Set ();
sortedPrimaryChannels = [];
2024-07-20 05:10:50 +02:00
// store & add
addChatModel = ( chatModel ) => {
2024-07-20 16:49:01 +02:00
this . chatModels . add ( chatModel );
this . updateIndices ();
2024-07-20 05:10:50 +02:00
};
createChat = ( primaryChannel ) => {
const id = v4_default ();
2024-07-20 20:42:43 +02:00
const chatModel = new ChatModel (
this . storageModel ,
this . connectionModel ,
this . settingsModel ,
this ,
id
);
2024-07-20 05:10:50 +02:00
chatModel . setPrimaryChannel ( primaryChannel );
this . addChatModel ( chatModel );
return chatModel ;
};
untrackChat = ( chat ) => {
2024-07-20 16:49:01 +02:00
this . chatModels . delete ( chat );
this . updateIndices ();
};
// sorting
updateIndices = () => {
this . sortedPrimaryChannels = [];
let allChannels = [];
for ( const chatModel of this . chatModels ) {
allChannels . push ( chatModel . info . primaryChannel );
}
2024-07-20 18:58:25 +02:00
this . sortedPrimaryChannels = allChannels . sort ( localeCompare );
2024-07-20 05:10:50 +02:00
};
2024-07-20 20:42:43 +02:00
getIndexOfPrimaryChannel ( primaryChannel ) {
return this . sortedPrimaryChannels . indexOf ( primaryChannel );
}
2024-07-20 05:10:50 +02:00
// restore
loadChats = () => {
const chatDir = storageKeys . chats ;
const chatIds = this . storageModel . list ( chatDir );
for ( const chatId of chatIds ) {
2024-07-20 20:42:43 +02:00
const chatModel = new ChatModel (
this . storageModel ,
this . connectionModel ,
this . settingsModel ,
this ,
chatId
);
2024-07-20 05:10:50 +02:00
this . addChatModel ( chatModel );
}
};
// init
2024-07-20 20:42:43 +02:00
constructor ( storageModel2 , settingsModel2 , connectionModel2 ) {
2024-07-20 05:10:50 +02:00
this . storageModel = storageModel2 ;
2024-07-20 20:42:43 +02:00
this . settingsModel = settingsModel2 ;
this . connectionModel = connectionModel2 ;
2024-07-20 05:10:50 +02:00
this . loadChats ();
}
};
2024-07-20 14:16:26 +02:00
// src/ViewModel/chatViewModel.tsx
var ChatViewModel = class {
chatModel ;
2024-07-20 16:34:16 +02:00
storageModel ;
2024-07-20 21:10:06 +02:00
settingsViewModel ;
2024-07-20 20:42:43 +02:00
chatListViewModel ;
2024-07-20 14:16:26 +02:00
// state
2024-07-20 16:49:01 +02:00
index = new State ( 0 );
2024-07-20 14:16:26 +02:00
primaryChannel = new State ( "" );
primaryChannelInput = new State ( "" );
2024-07-20 18:49:05 +02:00
secondaryChannels = new ListState ();
newSecondaryChannelInput = new State ( "" );
2024-07-20 19:18:19 +02:00
encryptionKeyInput = new State ( "" );
shouldShowEncryptionKey = new State ( false );
encryptionKeyInputType = createProxyState (
[ this . shouldShowEncryptionKey ],
() => this . shouldShowEncryptionKey . value == true ? "text" : "password"
);
2024-07-20 18:10:42 +02:00
color = new State ( "standard" /* Standard */ );
2024-07-20 16:28:00 +02:00
selectedPage = new State (
2024-07-20 16:34:16 +02:00
"messages" /* Messages */
2024-07-20 16:28:00 +02:00
);
2024-07-20 20:42:43 +02:00
composingMessage = new State ( "" );
2024-07-20 14:16:26 +02:00
// guards
cannotSetPrimaryChannel = createProxyState (
[ this . primaryChannel , this . primaryChannelInput ],
() => this . primaryChannelInput . value == "" || this . primaryChannelInput . value == this . primaryChannel . value
);
2024-07-20 19:18:19 +02:00
cannotSetEncryptionKey ;
2024-07-20 21:10:06 +02:00
cannotSendMessage ;
2024-07-20 16:49:01 +02:00
// sorting
updateIndex = () => {
2024-07-20 20:42:43 +02:00
this . index . value = this . chatModel . index ;
2024-07-20 16:49:01 +02:00
};
2024-07-20 20:42:43 +02:00
// view
2024-07-20 14:16:26 +02:00
open = () => {
this . chatListViewModel . openChat ( this );
};
2024-07-20 15:49:58 +02:00
close = () => {
this . chatListViewModel . closeChat ();
};
2024-07-20 20:42:43 +02:00
// settings
2024-07-20 17:30:36 +02:00
setPrimaryChannel = () => {
this . chatModel . setPrimaryChannel ( this . primaryChannelInput . value );
this . primaryChannel . value = this . chatModel . info . primaryChannel ;
this . chatListViewModel . updateIndices ();
};
2024-07-20 18:49:05 +02:00
addSecondaryChannel = () => {
this . secondaryChannels . add ( this . newSecondaryChannelInput . value );
this . newSecondaryChannelInput . value = "" ;
this . storeSecondaryChannels ();
2024-07-20 18:58:25 +02:00
this . restoreSecondaryChannels ();
2024-07-20 18:49:05 +02:00
};
removeSecondaryChannel = ( secondaryChannel ) => {
this . secondaryChannels . remove ( secondaryChannel );
this . storeSecondaryChannels ();
};
storeSecondaryChannels = () => {
this . chatModel . setSecondaryChannels ([
... this . secondaryChannels . value . values ()
]);
};
2024-07-20 19:18:19 +02:00
setEncryptionKey = () => {
this . chatModel . setEncryptionKey ( this . encryptionKeyInput . value );
this . encryptionKeyInput . callSubscriptions ();
};
2024-07-20 18:10:42 +02:00
setColor = ( newColor ) => {
this . color . value = newColor ;
this . chatModel . setColor ( newColor );
};
2024-07-20 20:48:13 +02:00
remove = () => {
this . close ();
this . chatModel . delete ();
this . chatListViewModel . restoreChats ();
};
2024-07-20 21:10:06 +02:00
// messaging
sendMessage = () => {
this . chatModel . sendMessage ( this . composingMessage . value );
this . composingMessage . value = "" ;
};
2024-07-20 16:34:16 +02:00
// restore
restorePageSelection = () => {
const path = storageKeys . chatLastUsedPage ( this . chatModel . id );
const lastUsedPage = this . storageModel . restore ( path );
if ( lastUsedPage != null ) {
this . selectedPage . value = lastUsedPage ;
}
this . selectedPage . subscribeSilent (( newPage ) => {
this . storageModel . store ( path , newPage );
});
};
2024-07-20 18:58:25 +02:00
restoreSecondaryChannels = () => {
this . secondaryChannels . clear ();
2024-07-20 19:18:19 +02:00
for ( const secondaryChannel of this . chatModel . info . secondaryChannels . sort (
localeCompare
)) {
2024-07-20 18:58:25 +02:00
this . secondaryChannels . add ( secondaryChannel );
}
};
2024-07-20 14:16:26 +02:00
// init
2024-07-20 21:10:06 +02:00
constructor ( chatModel , storageModel2 , settingsViewModel2 , chatListViewModel2 ) {
2024-07-20 14:16:26 +02:00
this . chatModel = chatModel ;
2024-07-20 20:42:43 +02:00
this . storageModel = storageModel2 ;
2024-07-20 21:10:06 +02:00
this . settingsViewModel = settingsViewModel2 ;
2024-07-20 14:16:26 +02:00
this . chatListViewModel = chatListViewModel2 ;
this . primaryChannel . value = chatModel . info . primaryChannel ;
this . primaryChannelInput . value = chatModel . info . primaryChannel ;
2024-07-20 19:18:19 +02:00
this . encryptionKeyInput . value = chatModel . info . encryptionKey ;
this . cannotSetEncryptionKey = createProxyState (
[ this . encryptionKeyInput ],
() => this . encryptionKeyInput . value == this . chatModel . info . encryptionKey
);
2024-07-20 21:10:06 +02:00
this . cannotSendMessage = createProxyState (
2024-07-20 21:15:06 +02:00
[ this . settingsViewModel . username , this . composingMessage ],
() => this . settingsViewModel . username . value == "" || this . composingMessage . value == ""
2024-07-20 21:10:06 +02:00
);
2024-07-20 18:10:42 +02:00
this . color . value = chatModel . color ;
2024-07-20 18:58:25 +02:00
this . restoreSecondaryChannels ();
2024-07-20 16:34:16 +02:00
this . restorePageSelection ();
2024-07-20 16:49:01 +02:00
this . updateIndex ();
2024-07-20 14:16:26 +02:00
}
};
2024-07-20 05:10:50 +02:00
// src/ViewModel/chatListViewModel.tsx
var ChatListViewModel = class {
chatListModel ;
2024-07-20 20:42:43 +02:00
storageModel ;
2024-07-20 21:10:06 +02:00
settingsViewModel ;
2024-07-20 05:10:50 +02:00
// state
newChatPrimaryChannel = new State ( "" );
2024-07-20 14:16:26 +02:00
chatViewModels = new ListState ();
selectedChat = new State ( void 0 );
2024-07-20 05:10:50 +02:00
// guards
cannotCreateChat = createProxyState (
[ this . newChatPrimaryChannel ],
() => this . newChatPrimaryChannel . value == ""
);
// methods
createChat = () => {
const chatModel = this . chatListModel . createChat (
this . newChatPrimaryChannel . value
);
this . newChatPrimaryChannel . value = "" ;
2024-07-20 20:42:43 +02:00
const chatViewModel = this . createChatViewModel ( chatModel );
2024-07-20 14:16:26 +02:00
this . chatViewModels . add ( chatViewModel );
2024-07-20 20:42:43 +02:00
this . updateIndices ();
2024-07-20 05:10:50 +02:00
};
2024-07-20 14:16:26 +02:00
untrackChat = ( chatViewModel ) => {
this . chatListModel . untrackChat ( chatViewModel . chatModel );
this . chatViewModels . remove ( chatViewModel );
};
2024-07-20 20:42:43 +02:00
createChatViewModel = ( chatModel ) => {
2024-07-20 21:10:06 +02:00
return new ChatViewModel (
chatModel ,
this . storageModel ,
this . settingsViewModel ,
this
);
2024-07-20 20:42:43 +02:00
};
// view
2024-07-20 14:16:26 +02:00
openChat = ( chatViewModel ) => {
this . selectedChat . value = chatViewModel ;
};
closeChat = () => {
this . selectedChat . value = void 0 ;
2024-07-20 05:10:50 +02:00
};
2024-07-20 20:42:43 +02:00
// sorting
updateIndices = () => {
for ( const chatViewModel of this . chatViewModels . value ) {
chatViewModel . updateIndex ();
}
};
2024-07-20 05:10:50 +02:00
// restore
restoreChats = () => {
2024-07-20 20:48:13 +02:00
this . chatViewModels . clear ();
2024-07-20 14:16:26 +02:00
for ( const chatModel of this . chatListModel . chatModels . values ()) {
2024-07-20 20:42:43 +02:00
const chatViewModel = this . createChatViewModel ( chatModel );
2024-07-20 14:16:26 +02:00
this . chatViewModels . add ( chatViewModel );
2024-07-20 05:10:50 +02:00
}
};
// init
2024-07-20 21:10:06 +02:00
constructor ( chatListModel2 , storageModel2 , settingsViewModel2 ) {
2024-07-20 20:42:43 +02:00
this . chatListModel = chatListModel2 ;
2024-07-20 14:16:26 +02:00
this . storageModel = storageModel2 ;
2024-07-20 21:10:06 +02:00
this . settingsViewModel = settingsViewModel2 ;
2024-07-20 05:10:50 +02:00
this . restoreChats ();
}
};
2024-07-20 16:28:00 +02:00
// src/View/Components/chatViewToggleButton.tsx
function ChatViewToggleButton ( label , icon , page , chatViewModel ) {
function select () {
chatViewModel . selectedPage . value = page ;
}
const isSelected = createProxyState (
[ chatViewModel . selectedPage ],
() => chatViewModel . selectedPage . value == page
);
return /* @__PURE__ */ createElement (
"button" ,
{
class : "ghost" ,
"aria-label" : label ,
"toggle:selected" : isSelected ,
"on:click" : select
},
/* @__PURE__ */ createElement ( "span" , { class : "icon" }, icon )
);
}
2024-07-20 02:30:45 +02:00
// src/View/translations.ts
var englishTranslations = {
general : {
2024-07-20 22:48:57 +02:00
closeButtonAudioLabel : "Close" ,
2024-07-20 17:30:36 +02:00
deleteItemButtonAudioLabel : "delete item" ,
setButton : "Set"
2024-07-20 02:30:45 +02:00
},
regional : {
weekdays : {
full : [
"Sunday" ,
"Monday" ,
"Tuesday" ,
"Wednesday" ,
"Thursday" ,
"Friday" ,
"Saturday"
],
2024-07-20 16:28:00 +02:00
abbreviated : [ "Sun" , "Mon" , "Tue" , "Wed" , "Thu" , "Fri" , "Sat" ]
2024-07-20 02:30:45 +02:00
}
},
homePage : {
appName : "Comms" ,
///
overviewHeadline : "Overview" ,
serverAddress : "Server address" ,
serverAddressPlaceholder : "wss://192.168.0.69:3000" ,
connectAudioLabel : "connect to server" ,
disconnectAudioLabel : "disconnect from server" ,
manageConnectionsAudioLabel : "manage connections" ,
mailboxHeadline : "Server Mailbox" ,
mailboxDisabled : "Mailbox disabled. You will miss out on messages sent while you're away" ,
mailboxEnabled : "Mailbox enabled. If you disconnect, the server will keep your messages temporarily" ,
outboxHeadline : "Outbox" ,
outboxAllItemsSent : "All items sent" ,
yourNameLabel : "Your name" ,
yourNamePlaceholder : "Jane Doe" ,
2024-07-20 17:30:36 +02:00
setNameButtonAudioLabel : "set name" ,
2024-07-20 02:30:45 +02:00
firstDayOfWeekLabel : "First day of week" ,
scrollToChatButton : "Chats" ,
///
backToOverviewAudioLabel : "go back to overview" ,
chatsHeadline : "Chats" ,
addChatAudioLabel : "name of new chat" ,
addChatPlaceholder : "Add chat" ,
addChatButton : "Add chat"
},
2024-07-20 02:56:44 +02:00
connectionModal : {
2024-07-20 03:39:47 +02:00
connectionModalHeadline : "Manage Connections" ,
2024-07-20 02:30:45 +02:00
///
2024-07-20 03:39:47 +02:00
connectButtonAudioLabel : "connect"
2024-07-20 14:16:26 +02:00
},
2024-07-20 15:49:58 +02:00
chatPage : {
closeChatAudioLabe : "close chat" ,
2024-07-20 16:28:00 +02:00
chatSettingsAudioLabel : "chat settings" ,
pages : {
settings : "Settings" ,
messages : "Messages" ,
allObjects : "All objects" ,
kanban : "Kanban" ,
calendar : "Calendar" ,
progress : "Progress"
2024-07-20 17:19:10 +02:00
},
settings : {
2024-07-20 17:30:36 +02:00
settingsHeadline : "Settings" ,
primaryChannelLabel : "Primary channel" ,
2024-07-20 18:49:05 +02:00
setPrimaryChannelButtonAudioLabel : "set primary channel" ,
newSecondaryChannelPlaceholder : "Add secondary channel" ,
newSecondaryChannelAudioLabel : "name of new secondary channel" ,
2024-07-20 19:18:19 +02:00
addSecondaryChannelButtonAudioLabel : "add secondary channel" ,
encryptionKeyLabel : "Encryption key" ,
setEncryptionKeyButtonAudioLabel : "set encryption key" ,
2024-07-20 20:48:13 +02:00
showEncryptionKey : "Show encryption key" ,
deleteChatButton : "Delete entire chat"
2024-07-20 21:15:06 +02:00
},
message : {
composerInputPlaceholder : "Type a message..." ,
sendMessageButtonAudioLabel : "send message"
2024-07-20 16:28:00 +02:00
}
2024-07-20 15:49:58 +02:00
}
2024-07-20 02:30:45 +02:00
};
var allTranslations = {
en : englishTranslations
};
var language = navigator . language . substring ( 0 , 2 );
var translations = allTranslations [ language ] || allTranslations . en ;
2024-07-20 21:15:06 +02:00
// src/View/ChatPages/messagePage.tsx
function MessagePage ( chatViewModel ) {
return /* @__PURE__ */ createElement ( "div" , { id : "message-page" }, /* @__PURE__ */ createElement ( "div" , { class : "toolbar" }, /* @__PURE__ */ createElement ( "span" , { "subscribe:innerText" : chatViewModel . primaryChannel })), /* @__PURE__ */ createElement ( "div" , { class : "content" }, /* @__PURE__ */ createElement ( "div" , { id : "message-container" }), /* @__PURE__ */ createElement ( "div" , { id : "composer" }, /* @__PURE__ */ createElement (
"input" ,
{
"bind:value" : chatViewModel . composingMessage ,
"on:enter" : chatViewModel . sendMessage ,
placeholder : translations . chatPage . message . composerInputPlaceholder
}
), /* @__PURE__ */ createElement (
"button" ,
{
class : "primary" ,
"aria-label" : translations . chatPage . message . sendMessageButtonAudioLabel ,
"on:click" : chatViewModel . sendMessage ,
"toggle:disabled" : chatViewModel . cannotSendMessage
},
/* @__PURE__ */ createElement ( "span" , { class : "icon" }, "send" )
))));
}
2024-07-20 18:49:05 +02:00
// src/View/Components/deletableListItem.tsx
function DeletableListItem ( text , primaryButton , ondelete ) {
return /* @__PURE__ */ createElement ( "div" , { class : "tile flex-row justify-apart align-center padding-0" }, /* @__PURE__ */ createElement ( "span" , { class : "padding-h" }, text ), /* @__PURE__ */ createElement ( "div" , { class : "flex-row justify-end" }, primaryButton , /* @__PURE__ */ createElement (
"button" ,
{
class : "danger" ,
"aria-label" : translations . general . deleteItemButtonAudioLabel ,
"on:click" : ondelete
},
/* @__PURE__ */ createElement ( "span" , { class : "icon" }, "delete" )
)));
}
2024-07-20 17:19:10 +02:00
// src/View/ChatPages/settingsPage.tsx
function SettingsPage ( chatViewModel ) {
2024-07-20 18:49:05 +02:00
const secondaryChannelConverter = ( secondaryChannel ) => {
return DeletableListItem ( secondaryChannel , /* @__PURE__ */ createElement ( "span" , null ), () => {
chatViewModel . removeSecondaryChannel ( secondaryChannel );
});
};
2024-07-20 19:18:19 +02:00
return /* @__PURE__ */ createElement ( "div" , null , /* @__PURE__ */ createElement ( "div" , { class : "toolbar" }, /* @__PURE__ */ createElement ( "span" , null , translations . chatPage . settings . settingsHeadline )), /* @__PURE__ */ createElement ( "div" , { class : "content" }, /* @__PURE__ */ createElement ( "label" , { class : "tile flex-no" }, /* @__PURE__ */ createElement ( "span" , { class : "icon" }, "forum" ), /* @__PURE__ */ createElement ( "div" , null , /* @__PURE__ */ createElement ( "span" , null , translations . chatPage . settings . primaryChannelLabel ), /* @__PURE__ */ createElement (
2024-07-20 17:30:36 +02:00
"input" ,
{
"bind:value" : chatViewModel . primaryChannelInput ,
"on:enter" : chatViewModel . setPrimaryChannel
}
))), /* @__PURE__ */ createElement ( "div" , { class : "flex-row justify-end width-input" }, /* @__PURE__ */ createElement (
"button" ,
{
class : "width-50" ,
"aria-label" : translations . chatPage . settings . setPrimaryChannelButtonAudioLabel ,
"on:click" : chatViewModel . setPrimaryChannel ,
"toggle:disabled" : chatViewModel . cannotSetPrimaryChannel
},
translations . general . setButton ,
/* @__PURE__ */ createElement ( "span" , { class : "icon" }, "check" )
2024-07-20 18:49:05 +02:00
)), /* @__PURE__ */ createElement ( "hr" , null ), /* @__PURE__ */ createElement ( "div" , { class : "flex-row width-input margin-bottom" }, /* @__PURE__ */ createElement (
"input" ,
{
"aria-label" : translations . chatPage . settings . newSecondaryChannelAudioLabel ,
placeholder : translations . chatPage . settings . newSecondaryChannelPlaceholder ,
"bind:value" : chatViewModel . newSecondaryChannelInput ,
"on:enter" : chatViewModel . addSecondaryChannel
}
), /* @__PURE__ */ createElement (
"button" ,
2024-07-20 18:10:42 +02:00
{
2024-07-20 18:49:05 +02:00
class : "primary" ,
"aria-label" : translations . chatPage . settings . addSecondaryChannelButtonAudioLabel ,
"on:click" : chatViewModel . addSecondaryChannel
2024-07-20 18:10:42 +02:00
},
2024-07-20 18:49:05 +02:00
/* @__PURE__ */ createElement ( "span" , { class : "icon" }, "add" )
)), /* @__PURE__ */ createElement (
"div" ,
{
class : "flex-column gap width-input" ,
"children:append" : [
chatViewModel . secondaryChannels ,
secondaryChannelConverter
]
}
2024-07-20 19:18:19 +02:00
), /* @__PURE__ */ createElement ( "hr" , null ), /* @__PURE__ */ createElement ( "label" , { class : "tile flex-no" }, /* @__PURE__ */ createElement ( "span" , { class : "icon" }, "key" ), /* @__PURE__ */ createElement ( "div" , null , /* @__PURE__ */ createElement ( "span" , null , translations . chatPage . settings . encryptionKeyLabel ), /* @__PURE__ */ createElement (
"input" ,
{
"bind:value" : chatViewModel . encryptionKeyInput ,
"on:enter" : chatViewModel . setEncryptionKey ,
"set:type" : chatViewModel . encryptionKeyInputType
}
))), /* @__PURE__ */ createElement ( "div" , { class : "flex-row justify-end width-input" }, /* @__PURE__ */ createElement (
"button" ,
{
class : "width-50" ,
"aria-label" : translations . chatPage . settings . setEncryptionKeyButtonAudioLabel ,
"on:click" : chatViewModel . setEncryptionKey ,
"toggle:disabled" : chatViewModel . cannotSetEncryptionKey
},
translations . general . setButton ,
/* @__PURE__ */ createElement ( "span" , { class : "icon" }, "check" )
)), /* @__PURE__ */ createElement ( "label" , { class : "inline" }, /* @__PURE__ */ createElement (
"input" ,
{
type : "checkbox" ,
"bind:checked" : chatViewModel . shouldShowEncryptionKey
}
), translations . chatPage . settings . showEncryptionKey ), /* @__PURE__ */ createElement ( "hr" , null ), /* @__PURE__ */ createElement ( "div" , { class : "flex-row gap width-input" }, ... Object . values ( Color ). map (( color ) => {
2024-07-20 18:49:05 +02:00
const isSelected = createProxyState (
[ chatViewModel . color ],
() => chatViewModel . color . value == color
);
function setColor () {
chatViewModel . setColor ( color );
}
return /* @__PURE__ */ createElement (
"button" ,
{
color ,
class : "fill-color width-100 flex" ,
style : "height: 2rem" ,
"toggle:selected" : isSelected ,
"on:click" : setColor
2024-07-20 18:10:42 +02:00
}
2024-07-20 18:49:05 +02:00
);
2024-07-20 20:48:13 +02:00
})), /* @__PURE__ */ createElement ( "hr" , null ), /* @__PURE__ */ createElement ( "button" , { class : "danger width-input flex-no" , "on:click" : chatViewModel . remove }, translations . chatPage . settings . deleteChatButton , /* @__PURE__ */ createElement ( "span" , { class : "icon" }, "delete_forever" ))));
2024-07-20 17:19:10 +02:00
}
2024-07-20 15:49:58 +02:00
// src/View/chatPage.tsx
function ChatPage ( chatViewModel ) {
2024-07-20 17:19:10 +02:00
const mainContent = new State ( /* @__PURE__ */ createElement ( "div" , null ));
chatViewModel . selectedPage . subscribe (( selectedPage ) => {
switch ( selectedPage ) {
case "settings" /* Settings */ :
return mainContent . value = SettingsPage ( chatViewModel );
default :
return mainContent . value = MessagePage ( chatViewModel );
}
});
2024-07-20 22:16:37 +02:00
return /* @__PURE__ */ createElement ( "article" , { id : "chat-page" , "set:color" : chatViewModel . color , class : "subtle-background" }, /* @__PURE__ */ createElement ( "div" , null , /* @__PURE__ */ createElement ( "div" , { id : "ribbon" }, /* @__PURE__ */ createElement (
2024-07-20 15:49:58 +02:00
"button" ,
{
2024-07-20 16:28:00 +02:00
class : "ghost" ,
2024-07-20 15:49:58 +02:00
"aria-label" : translations . chatPage . closeChatAudioLabe ,
"on:click" : chatViewModel . close
},
/* @__PURE__ */ createElement ( "span" , { class : "icon" }, "close" )
2024-07-20 19:26:13 +02:00
), /* @__PURE__ */ createElement ( "span" , null , ChatViewToggleButton (
2024-07-20 16:28:00 +02:00
translations . chatPage . pages . calendar ,
"calendar_month" ,
2024-07-20 16:34:16 +02:00
"calendar" /* Calendar */ ,
2024-07-20 16:28:00 +02:00
chatViewModel
), ChatViewToggleButton (
translations . chatPage . pages . progress ,
"window" ,
2024-07-20 16:34:16 +02:00
"progress" /* Progress */ ,
2024-07-20 16:28:00 +02:00
chatViewModel
), ChatViewToggleButton (
translations . chatPage . pages . kanban ,
"view_kanban" ,
2024-07-20 16:34:16 +02:00
"kanban" /* Kanban */ ,
2024-07-20 16:28:00 +02:00
chatViewModel
), ChatViewToggleButton (
translations . chatPage . pages . allObjects ,
"deployed_code" ,
2024-07-20 16:34:16 +02:00
"all" /* AllObjects */ ,
2024-07-20 16:28:00 +02:00
chatViewModel
), ChatViewToggleButton (
translations . chatPage . pages . messages ,
"forum" ,
2024-07-20 16:34:16 +02:00
"messages" /* Messages */ ,
2024-07-20 16:28:00 +02:00
chatViewModel
), ChatViewToggleButton (
translations . chatPage . pages . settings ,
"settings" ,
2024-07-20 16:34:16 +02:00
"settings" /* Settings */ ,
2024-07-20 16:28:00 +02:00
chatViewModel
2024-07-20 17:19:10 +02:00
))), /* @__PURE__ */ createElement ( "div" , { id : "main" , "children:set" : mainContent })));
2024-07-20 15:49:58 +02:00
}
// src/View/chatPageWrapper.tsx
function ChatPageWrapper ( chatListViewModel2 ) {
const chatPageContent = createProxyState (
[ chatListViewModel2 . selectedChat ],
() => {
if ( chatListViewModel2 . selectedChat . value == void 0 ) {
return /* @__PURE__ */ createElement ( "div" , null );
} else {
return ChatPage ( chatListViewModel2 . selectedChat . value );
}
}
);
const isShowingChat = createProxyState (
[ chatListViewModel2 . selectedChat ],
() => chatListViewModel2 . selectedChat . value != void 0
);
return /* @__PURE__ */ createElement (
"div" ,
{
id : "chat-page-wrapper" ,
"toggle:open" : isShowingChat ,
"children:set" : chatPageContent
}
);
}
2024-07-20 02:30:45 +02:00
// src/View/Modals/connectionModal.tsx
function ConnectionModal ( connectionViewModel2 ) {
2024-07-20 03:34:54 +02:00
const previousAddressConverter = ( address ) => {
2024-07-20 03:39:47 +02:00
function connnect () {
connectionViewModel2 . connectToAddress ( address );
}
const cannotConnect = createProxyState (
[ connectionViewModel2 . isConnected ],
2024-07-20 22:44:23 +02:00
() => connectionViewModel2 . isConnected . value == true && connectionViewModel2 . connectionModel . address == address
2024-07-20 03:39:47 +02:00
);
return DeletableListItem (
address ,
/* @__PURE__ */ createElement (
"button" ,
{
class : "primary" ,
"on:click" : connnect ,
"toggle:disabled" : cannotConnect ,
"aria-label" : translations . connectionModal . connectButtonAudioLabel
},
/* @__PURE__ */ createElement ( "span" , { class : "icon" }, "link" )
),
() => {
connectionViewModel2 . removePreviousAddress ( address );
}
);
2024-07-20 03:34:54 +02:00
};
2024-07-20 02:30:45 +02:00
return /* @__PURE__ */ createElement (
"div" ,
{
class : "modal" ,
"toggle:open" : connectionViewModel2 . isShowingConnectionModal
},
2024-07-20 03:34:54 +02:00
/* @__PURE__ */ createElement ( "div" , null , /* @__PURE__ */ createElement ( "main" , null , /* @__PURE__ */ createElement ( "h2" , null , translations . connectionModal . connectionModalHeadline ), /* @__PURE__ */ createElement (
"div" ,
{
class : "flex-column gap" ,
"children:append" : [
connectionViewModel2 . previousAddresses ,
previousAddressConverter
]
}
)), /* @__PURE__ */ createElement ( "button" , { "on:click" : connectionViewModel2 . hideConnectionModal }, translations . general . closeButtonAudioLabel , /* @__PURE__ */ createElement ( "span" , { class : "icon" }, "close" )))
2024-07-20 02:30:45 +02:00
);
}
2024-07-09 15:15:17 +02:00
// node_modules/udn-frontend/index.ts
var UDNFrontend = class {
ws ;
// HANDLERS
connectionHandler = () => {
};
disconnectionHandler = () => {
};
messageHandler = ( data ) => {
};
2024-07-19 18:00:01 +02:00
mailboxHandler = ( mailboxId ) => {
2024-07-09 15:15:17 +02:00
};
2024-07-19 18:00:01 +02:00
mailboxConnectionHandler = ( mailboxId ) => {
2024-07-09 15:15:17 +02:00
};
2024-07-19 18:00:01 +02:00
mailboxDeleteHandler = ( mailboxId ) => {
2024-07-09 15:15:17 +02:00
};
// 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
2024-07-19 18:17:00 +02:00
connect ( address ) {
2024-07-09 15:15:17 +02:00
try {
this . disconnect ();
2024-07-19 18:17:00 +02:00
this . ws = new WebSocket ( address );
2024-07-09 15:15:17 +02:00
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 );
}
2024-07-19 18:00:01 +02:00
connectMailbox ( mailboxId ) {
2024-07-09 15:15:17 +02:00
const messageObject = {
2024-07-19 18:00:01 +02:00
requestedMailbox : mailboxId
2024-07-09 15:15:17 +02:00
};
return this . send ( messageObject );
}
2024-07-19 18:00:01 +02:00
deleteMailbox ( mailboxId ) {
2024-07-09 15:15:17 +02:00
const messageObject = {
2024-07-19 18:00:01 +02:00
deletingMailbox : mailboxId
2024-07-09 15:15:17 +02:00
};
return this . send ( messageObject );
}
};
2024-07-19 18:00:01 +02:00
// src/Model/connectionModel.ts
var ConnectionModel = class {
udn ;
2024-07-20 02:56:44 +02:00
storageModel ;
2024-07-19 18:00:01 +02:00
// data
get isConnected () {
return this . udn . ws != void 0 && this . udn . ws . readyState == 1 ;
2024-07-13 17:13:59 +02:00
}
2024-07-19 18:02:23 +02:00
get address () {
2024-07-19 18:00:01 +02:00
return this . udn . ws ? . url ;
2024-07-13 17:13:59 +02:00
}
2024-07-20 22:44:23 +02:00
connectionChangeHandler = () => {
};
messageHandler = () => {
};
2024-07-19 18:00:01 +02:00
// connection
2024-07-19 18:17:00 +02:00
connect = ( address ) => {
this . udn . connect ( address );
2024-07-19 18:02:23 +02:00
};
disconnect = () => {
2024-07-19 18:00:01 +02:00
this . udn . disconnect ();
2024-07-19 18:02:23 +02:00
};
2024-07-20 20:42:43 +02:00
handleMessage = ( data ) => {
2024-07-20 22:44:23 +02:00
this . messageHandler ( data );
2024-07-20 20:42:43 +02:00
};
2024-07-19 18:02:23 +02:00
handleConnectionChange = () => {
console . log ( "connection status:" , this . isConnected , this . address );
2024-07-20 22:44:23 +02:00
this . connectionChangeHandler ();
2024-07-20 02:56:44 +02:00
if ( this . isConnected == false ) return ;
if ( this . address ) {
this . storeAddress ( this . address );
}
2024-07-20 22:44:23 +02:00
this . sendMessagesInOutbox ();
2024-07-19 18:02:23 +02:00
};
2024-07-20 20:42:43 +02:00
// outbox
getOutboxMessags = () => {
const outboxPath = storageKeys . outbox ;
const messageIds = this . storageModel . list ( outboxPath );
let messages = [];
for ( const messageId of messageIds ) {
const message = this . storageModel . restoreStringifiable ([
... outboxPath ,
messageId
]);
if ( message == void 0 ) continue ;
if ( checkIsValidObject ( message ) == false ) continue ;
2024-07-20 22:44:23 +02:00
messages . push ( message );
2024-07-20 20:42:43 +02:00
}
return messages ;
};
addToOutbox = ( chatMessage ) => {
const messagePath = [... storageKeys . outbox , chatMessage . id ];
this . storageModel . storeStringifiable ( messagePath , chatMessage );
};
removeFromOutbox = ( chatMessage ) => {
const messagePath = [... storageKeys . outbox , chatMessage . id ];
this . storageModel . remove ( messagePath );
};
sendMessagesInOutbox = () => {
const messages = this . getOutboxMessags ();
for ( const message of messages ) {
const isSent = this . tryToSendMessage ( message );
if ( isSent == false ) return ;
this . removeFromOutbox ( message );
}
};
2024-07-19 18:00:01 +02:00
// messaging
2024-07-20 20:42:43 +02:00
sendMessageOrStore = ( chatMessage ) => {
const isSent = this . tryToSendMessage ( chatMessage );
if ( isSent == true ) return ;
this . addToOutbox ( chatMessage );
};
tryToSendMessage = ( chatMessage ) => {
2024-07-19 18:00:01 +02:00
const stringifiedBody = stringify ( chatMessage );
return this . udn . sendMessage ( chatMessage . channel , stringifiedBody );
2024-07-19 18:02:23 +02:00
};
2024-07-20 02:56:44 +02:00
// storage
getAddressPath = ( address ) => {
const dirPath = storageKeys . previousAddresses ;
return [... dirPath , address ];
};
storeAddress = ( address ) => {
const addressPath = this . getAddressPath ( address );
this . storageModel . store ( addressPath , "" );
};
removeAddress = ( address ) => {
const addressPath = this . getAddressPath ( address );
this . storageModel . remove ( addressPath );
};
2024-07-20 02:59:40 +02:00
get addresses () {
2024-07-20 02:56:44 +02:00
const dirPath = storageKeys . previousAddresses ;
return this . storageModel . list ( dirPath );
2024-07-20 02:59:40 +02:00
}
2024-07-20 22:44:23 +02:00
// handlers
setConnectionChangeHandler = ( handler ) => {
this . connectionChangeHandler = handler ;
};
setMessageHandler = ( handler ) => {
this . messageHandler = handler ;
};
2024-07-19 18:00:01 +02:00
// setup
2024-07-20 20:42:43 +02:00
constructor ( storageModel2 ) {
2024-07-19 18:00:01 +02:00
this . udn = new UDNFrontend ();
2024-07-20 20:42:43 +02:00
this . storageModel = storageModel2 ;
2024-07-19 18:17:00 +02:00
this . udn . onmessage = ( data ) => {
2024-07-20 20:42:43 +02:00
this . handleMessage ( data );
2024-07-19 18:17:00 +02:00
};
this . udn . onconnect = () => {
this . handleConnectionChange ();
};
this . udn . ondisconnect = () => {
this . handleConnectionChange ();
};
2024-07-09 17:23:29 +02:00
}
};
2024-07-09 17:27:15 +02:00
2024-07-20 02:18:15 +02:00
// src/ViewModel/connectionViewModel.tsx
var ConnectionViewModel = class {
connectionModel ;
// state
serverAddressInput = new State ( "" );
isConnected = new State ( false );
2024-07-20 02:30:45 +02:00
isShowingConnectionModal = new State ( false );
2024-07-20 02:56:44 +02:00
previousAddresses = new ListState ();
2024-07-20 04:15:14 +02:00
// guards
2024-07-20 02:18:15 +02:00
cannotConnect = createProxyState (
[ this . serverAddressInput , this . isConnected ],
() => this . isConnected . value == true && this . serverAddressInput . value == this . connectionModel . address || this . serverAddressInput . value == ""
);
cannotDisonnect = createProxyState (
[ this . isConnected ],
() => this . isConnected . value == false
);
2024-07-20 04:15:14 +02:00
hasNoPreviousConnections = createProxyState (
[ this . previousAddresses ],
() => this . previousAddresses . value . size == 0
);
2024-07-20 02:18:15 +02:00
// handlers
connectionChangeHandler = () => {
this . isConnected . value = this . connectionModel . isConnected ;
2024-07-20 02:56:44 +02:00
if ( this . connectionModel . isConnected == false ) return ;
2024-07-20 02:18:15 +02:00
if ( this . connectionModel . address ) {
this . serverAddressInput . value = this . connectionModel . address ;
2024-07-20 22:44:23 +02:00
this . previousAddresses . add ( this . connectionModel . address );
2024-07-20 02:18:15 +02:00
}
};
messageHandler = ( data ) => {
};
// methods
connect = () => {
2024-07-20 03:39:47 +02:00
this . connectToAddress ( this . serverAddressInput . value );
};
connectToAddress = ( address ) => {
this . connectionModel . connect ( address );
2024-07-20 02:18:15 +02:00
};
disconnect = () => {
this . connectionModel . disconnect ();
};
2024-07-20 03:34:54 +02:00
removePreviousAddress = ( address ) => {
this . connectionModel . removeAddress ( address );
this . updatePreviousAddresses ();
};
2024-07-20 02:30:45 +02:00
// view methods
showConnectionModal = () => {
this . isShowingConnectionModal . value = true ;
};
hideConnectionModal = () => {
this . isShowingConnectionModal . value = false ;
};
2024-07-20 02:59:40 +02:00
updatePreviousAddresses = () => {
this . previousAddresses . clear ();
this . previousAddresses . add (... this . connectionModel . addresses );
};
2024-07-20 02:00:00 +02:00
// init
2024-07-20 20:42:43 +02:00
constructor ( connectionModel2 ) {
this . connectionModel = connectionModel2 ;
2024-07-20 02:59:40 +02:00
this . updatePreviousAddresses ();
2024-07-20 22:44:23 +02:00
connectionModel2 . setConnectionChangeHandler ( this . connectionChangeHandler );
connectionModel2 . setMessageHandler ( this . messageHandler );
2024-07-20 02:00:00 +02:00
}
};
2024-07-19 23:45:07 +02:00
2024-07-20 02:00:00 +02:00
// src/View/Components/option.tsx
function Option ( text , value , selectedOnCreate ) {
return /* @__PURE__ */ createElement ( "option" , { value , "toggle:selected" : selectedOnCreate }, text );
}
2024-07-20 02:56:44 +02:00
var StringToOption = ( string ) => {
return Option ( string , string , false );
};
2024-07-20 02:00:00 +02:00
2024-07-20 05:10:50 +02:00
// src/View/Components/chatEntry.tsx
2024-07-20 14:16:26 +02:00
function ChatEntry ( chatViewModel ) {
2024-07-20 18:10:42 +02:00
const view = /* @__PURE__ */ createElement ( "button" , { "set:color" : chatViewModel . color , class : "chat-entry tile" , "on:click" : chatViewModel . open }, /* @__PURE__ */ createElement (
2024-07-20 14:16:26 +02:00
"span" ,
{
class : "shadow" ,
"subscribe:innerText" : chatViewModel . primaryChannel
}
), /* @__PURE__ */ createElement ( "h2" , { "subscribe:innerText" : chatViewModel . primaryChannel }));
2024-07-20 16:49:01 +02:00
chatViewModel . index . subscribe (( newIndex ) => {
view . style . order = newIndex ;
});
return view ;
2024-07-20 05:10:50 +02:00
}
2024-07-20 14:16:26 +02:00
var ChatViewModelToChatEntry = ( chatViewModel ) => {
return ChatEntry ( chatViewModel );
2024-07-20 05:10:50 +02:00
};
2024-07-19 23:45:07 +02:00
// src/View/homePage.tsx
2024-07-20 05:10:50 +02:00
function HomePage ( settingsViewModel2 , connectionViewModel2 , chatListViewModel2 ) {
2024-07-20 02:18:15 +02:00
const overviewSection = /* @__PURE__ */ createElement ( "div" , { id : "overview-section" }, /* @__PURE__ */ createElement ( "h2" , null , translations . homePage . overviewHeadline ), /* @__PURE__ */ createElement ( "label" , { class : "tile flex-no" }, /* @__PURE__ */ createElement ( "span" , { class : "icon" }, "cell_tower" ), /* @__PURE__ */ createElement ( "div" , null , /* @__PURE__ */ createElement ( "span" , null , translations . homePage . serverAddress ), /* @__PURE__ */ createElement (
"input" ,
{
2024-07-20 02:56:44 +02:00
list : "previous-connection-list" ,
2024-07-20 02:20:09 +02:00
placeholder : translations . homePage . serverAddressPlaceholder ,
2024-07-20 02:18:15 +02:00
"bind:value" : connectionViewModel2 . serverAddressInput ,
"on:enter" : connectionViewModel2 . connect
}
2024-07-20 02:56:44 +02:00
), /* @__PURE__ */ createElement (
"datalist" ,
{
hidden : true ,
id : "previous-connection-list" ,
"children:append" : [
connectionViewModel2 . previousAddresses ,
StringToOption
]
}
2024-07-20 02:18:15 +02:00
))), /* @__PURE__ */ createElement ( "div" , { class : "flex-row" }, /* @__PURE__ */ createElement (
2024-07-20 01:14:21 +02:00
"button" ,
{
class : "danger flex justify-center" ,
2024-07-20 02:18:15 +02:00
"aria-label" : translations . homePage . disconnectAudioLabel ,
"on:click" : connectionViewModel2 . disconnect ,
"toggle:disabled" : connectionViewModel2 . cannotDisonnect
2024-07-20 01:14:21 +02:00
},
/* @__PURE__ */ createElement ( "span" , { class : "icon" }, "link_off" )
), /* @__PURE__ */ createElement (
"button" ,
{
class : "flex justify-center" ,
2024-07-20 02:30:45 +02:00
"aria-label" : translations . homePage . manageConnectionsAudioLabel ,
2024-07-20 04:15:14 +02:00
"on:click" : connectionViewModel2 . showConnectionModal ,
"toggle:disabled" : connectionViewModel2 . hasNoPreviousConnections
2024-07-20 01:14:21 +02:00
},
2024-07-20 04:13:43 +02:00
/* @__PURE__ */ createElement ( "span" , { class : "icon" }, "history" )
2024-07-20 01:14:21 +02:00
), /* @__PURE__ */ createElement (
"button" ,
{
class : "primary flex justify-center" ,
2024-07-20 02:18:15 +02:00
"aria-label" : translations . homePage . connectAudioLabel ,
"on:click" : connectionViewModel2 . connect ,
"toggle:disabled" : connectionViewModel2 . cannotConnect
2024-07-20 01:14:21 +02:00
},
/* @__PURE__ */ createElement ( "span" , { class : "icon" }, "link" )
2024-07-20 02:00:00 +02:00
)), /* @__PURE__ */ createElement ( "hr" , null ), /* @__PURE__ */ createElement ( "div" , { class : "tile flex-no" }, /* @__PURE__ */ createElement ( "span" , { class : "icon" }, "inbox" ), /* @__PURE__ */ createElement ( "div" , null , /* @__PURE__ */ createElement ( "b" , null , translations . homePage . mailboxHeadline ), /* @__PURE__ */ createElement ( "span" , { class : "error" }, translations . homePage . mailboxDisabled ))), /* @__PURE__ */ createElement ( "div" , { class : "tile flex-no" }, /* @__PURE__ */ createElement ( "span" , { class : "icon" }, "outbox" ), /* @__PURE__ */ createElement ( "div" , null , /* @__PURE__ */ createElement ( "b" , null , translations . homePage . outboxHeadline ), /* @__PURE__ */ createElement ( "span" , { class : "success" }, translations . homePage . outboxAllItemsSent ))), /* @__PURE__ */ createElement ( "hr" , null ), /* @__PURE__ */ createElement ( "label" , { class : "tile flex-no" }, /* @__PURE__ */ createElement ( "span" , { class : "icon" }, "account_circle" ), /* @__PURE__ */ createElement ( "div" , null , /* @__PURE__ */ createElement ( "span" , null , translations . homePage . yourNameLabel ), /* @__PURE__ */ createElement (
"input" ,
{
2024-07-20 02:20:09 +02:00
placeholder : translations . homePage . yourNamePlaceholder ,
2024-07-20 21:10:06 +02:00
"bind:value" : settingsViewModel2 . usernameInput ,
2024-07-20 02:00:00 +02:00
"on:enter" : settingsViewModel2 . setName
}
))), /* @__PURE__ */ createElement ( "div" , { class : "flex-row justify-end" }, /* @__PURE__ */ createElement (
"button" ,
{
class : "width-50" ,
"on:click" : settingsViewModel2 . setName ,
2024-07-20 17:30:36 +02:00
"toggle:disabled" : settingsViewModel2 . cannotSetName ,
"aria-label" : translations . homePage . setNameButtonAudioLabel
2024-07-20 02:00:00 +02:00
},
2024-07-20 17:30:36 +02:00
translations . general . setButton ,
2024-07-20 02:00:00 +02:00
/* @__PURE__ */ createElement ( "span" , { class : "icon" }, "check" )
)), /* @__PURE__ */ createElement ( "hr" , null ), /* @__PURE__ */ createElement ( "label" , { class : "tile flex-no" }, /* @__PURE__ */ createElement ( "span" , { class : "icon" }, "calendar_month" ), /* @__PURE__ */ createElement ( "div" , null , /* @__PURE__ */ createElement ( "span" , null , translations . homePage . firstDayOfWeekLabel ), /* @__PURE__ */ createElement ( "select" , { "bind:value" : settingsViewModel2 . firstDayOfWeekInput }, ... translations . regional . weekdays . full . map (
( weekdayName , i ) => Option (
weekdayName ,
i . toString (),
i == settingsViewModel2 . firstDayOfWeekInput . value
)
)), /* @__PURE__ */ createElement ( "span" , { class : "icon" }, "arrow_drop_down" ))), /* @__PURE__ */ createElement ( "div" , { class : "mobile-only" }, /* @__PURE__ */ createElement ( "hr" , null ), /* @__PURE__ */ createElement ( "div" , { class : "flex-row justify-end" }, /* @__PURE__ */ createElement ( "button" , { class : "ghost width-50" , "on:click" : scrollToChat }, translations . homePage . scrollToChatButton , /* @__PURE__ */ createElement ( "span" , { class : "icon" }, "arrow_forward" )))));
2024-07-20 00:15:05 +02:00
const chatSection = /* @__PURE__ */ createElement ( "div" , { id : "chat-section" }, /* @__PURE__ */ createElement ( "h2" , null , translations . homePage . chatsHeadline ), /* @__PURE__ */ createElement ( "div" , { class : "flex-row width-input" }, /* @__PURE__ */ createElement (
2024-07-19 23:45:07 +02:00
"input" ,
{
placeholder : translations . homePage . addChatPlaceholder ,
2024-07-20 05:10:50 +02:00
"aria-label" : translations . homePage . addChatAudioLabel ,
"bind:value" : chatListViewModel2 . newChatPrimaryChannel ,
"on:enter" : chatListViewModel2 . createChat
2024-07-19 23:45:07 +02:00
}
), /* @__PURE__ */ createElement (
"button" ,
{
class : "primary" ,
2024-07-20 05:10:50 +02:00
"aria-label" : translations . homePage . addChatButton ,
"on:click" : chatListViewModel2 . createChat ,
"toggle:disabled" : chatListViewModel2 . cannotCreateChat
2024-07-19 23:45:07 +02:00
},
/* @__PURE__ */ createElement ( "span" , { class : "icon" }, "add" )
2024-07-20 05:10:50 +02:00
)), /* @__PURE__ */ createElement (
"div" ,
{
2024-07-20 13:30:01 +02:00
id : "chat-grid" ,
2024-07-20 14:16:26 +02:00
"children:append" : [ chatListViewModel2 . chatViewModels , ChatViewModelToChatEntry ]
2024-07-20 05:10:50 +02:00
}
));
2024-07-20 00:15:05 +02:00
function scrollToChat () {
chatSection . scrollIntoView ();
}
return /* @__PURE__ */ createElement ( "article" , { id : "home-page" }, /* @__PURE__ */ createElement ( "header" , null , /* @__PURE__ */ createElement ( "span" , null , translations . homePage . appName )), /* @__PURE__ */ createElement ( "div" , null , overviewSection , chatSection ));
2024-07-19 23:45:07 +02:00
}
2024-07-20 02:00:00 +02:00
// src/Model/settingsModel.ts
var SettingsModel = class {
storageModel ;
username ;
firstDayOfWeek ;
// set
setName ( newValue ) {
this . username = newValue ;
const path = storageKeys . username ;
this . storageModel . store ( path , newValue );
}
setFirstDayOfWeek ( newValue ) {
this . firstDayOfWeek = newValue ;
const path = storageKeys . firstDayOfWeek ;
this . storageModel . storeStringifiable ( path , newValue );
}
// restore
restoreUsername () {
const path = storageKeys . username ;
const content = this . storageModel . restore ( path );
this . username = content ?? "" ;
}
restoreFirstDayofWeek () {
const path = storageKeys . firstDayOfWeek ;
const content = this . storageModel . restoreStringifiable ( path );
this . firstDayOfWeek = content ?? 0 ;
}
// init
constructor ( storageModel2 ) {
this . storageModel = storageModel2 ;
this . restoreUsername ();
this . restoreFirstDayofWeek ();
}
};
// src/ViewModel/settingsViewModel.ts
var SettingsViewModel = class {
settingsModel ;
// state
2024-07-20 21:10:06 +02:00
username = new State ( "" );
usernameInput = new State ( "" );
2024-07-20 02:00:00 +02:00
firstDayOfWeekInput = new State ( 0 );
2024-07-20 04:15:14 +02:00
// guards
2024-07-20 02:00:00 +02:00
cannotSetName = createProxyState (
2024-07-20 21:10:06 +02:00
[ this . usernameInput ],
() => this . usernameInput . value == "" || this . usernameInput . value == this . settingsModel . username
2024-07-20 02:00:00 +02:00
);
// set
setName = () => {
2024-07-20 21:10:06 +02:00
this . settingsModel . setName ( this . usernameInput . value );
this . username . value = this . settingsModel . username ;
this . usernameInput . callSubscriptions ();
2024-07-20 02:00:00 +02:00
};
setFirstDayofWeek = () => {
this . settingsModel . setFirstDayOfWeek ( this . firstDayOfWeekInput . value );
};
// init
2024-07-20 20:42:43 +02:00
constructor ( settingsModel2 ) {
this . settingsModel = settingsModel2 ;
2024-07-20 21:10:06 +02:00
this . username . value = settingsModel2 . username ;
this . usernameInput . value = settingsModel2 . username ;
2024-07-20 20:42:43 +02:00
this . firstDayOfWeekInput . value = settingsModel2 . firstDayOfWeek ;
2024-07-20 02:00:00 +02:00
this . firstDayOfWeekInput . subscribe ( this . setFirstDayofWeek );
}
};
2024-07-19 19:23:48 +02:00
// src/index.tsx
var storageModel = new StorageModel ();
2024-07-20 20:42:43 +02:00
var settingsModel = new SettingsModel ( storageModel );
var connectionModel = new ConnectionModel ( storageModel );
var chatListModel = new ChatListModel (
storageModel ,
settingsModel ,
connectionModel
);
2024-07-20 05:10:50 +02:00
storageModel . print ();
2024-07-20 20:42:43 +02:00
var settingsViewModel = new SettingsViewModel ( settingsModel );
var connectionViewModel = new ConnectionViewModel ( connectionModel );
2024-07-20 21:10:06 +02:00
var chatListViewModel = new ChatListViewModel (
chatListModel ,
storageModel ,
settingsViewModel
);
2024-07-20 14:54:52 +02:00
document . body . append ( /* @__PURE__ */ createElement ( "div" , { id : "background" }));
2024-07-20 02:30:45 +02:00
document . querySelector ( "main" ). append (
2024-07-20 05:10:50 +02:00
HomePage ( settingsViewModel , connectionViewModel , chatListViewModel ),
2024-07-20 14:16:26 +02:00
ChatPageWrapper ( chatListViewModel ),
2024-07-20 02:30:45 +02:00
ConnectionModal ( connectionViewModel )
);
2024-07-07 13:43:18 +02:00
})();