2023-12-27 17:25:49 +00:00
chatComponent = {
html : `
< div id = "videos" style = "pointer-events:none" > < / d i v >
< div id = "messages" aria - live = "assertive" aria - relevant > < / d i v >
< div id = "chatfooter" >
< div id = "chatbar" >
< input id = "chatline" type = "text" placeholder = "type here" > < / i n p u t >
< / d i v >
< button id = "showchat" class = "btn" > show chat < / b u t t o n >
< / d i v >
< / d i v >
` ,
init : ( el ) => new Proxy ( {
2024-01-03 14:23:34 +00:00
scene : null ,
visible : true ,
visibleChatbar : false ,
messages : [ ] ,
2023-12-27 17:25:49 +00:00
2024-01-03 14:23:34 +00:00
$videos : el . querySelector ( "#videos" ) ,
$messages : el . querySelector ( "#messages" ) ,
$chatline : el . querySelector ( "#chatline" ) ,
$chatbar : el . querySelector ( "#chatbar" ) ,
2023-12-27 17:25:49 +00:00
install ( opts ) {
this . opts = opts
this . scene = opts . scene
el . className = "xrf"
el . style . display = 'none' // start hidden
document . body . appendChild ( el )
2024-01-03 14:23:34 +00:00
this . visibleChatbar = false
2023-12-27 17:25:49 +00:00
document . dispatchEvent ( new CustomEvent ( "$chat:ready" , { detail : opts } ) )
2024-01-03 14:23:34 +00:00
this . send ( { message : ` Welcome to <b> ${ document . location . search . substr ( 1 ) } </b>, a 3D scene(file) which simply links to other ones.<br>You can start a solo offline exploration in XR right away.<br>Type /help below, or use the arrow- or WASD-keys on your keyboard, and mouse-drag to rotate.<br> ` , class : [ "info" , "guide" , "multiline" ] } )
2023-12-27 17:25:49 +00:00
} ,
initListeners ( ) {
2024-01-03 14:23:34 +00:00
let { $chatline } = this
2023-12-27 17:25:49 +00:00
$chatline . addEventListener ( 'keydown' , ( e ) => {
if ( e . key == 'Enter' ) {
2024-01-03 14:23:34 +00:00
if ( $chatline . value [ 0 ] != '/' ) {
document . dispatchEvent ( new CustomEvent ( "network.send" , { detail : { message : $chatline . value } } ) )
}
2023-12-27 17:25:49 +00:00
this . send ( { message : $chatline . value } )
$chatline . value = ''
}
} )
console . dir ( this . scene )
} ,
toggle ( ) {
this . visible = ! this . visible
if ( this . visible && window . meeting . status == 'offline' ) window . meeting . start ( this . opts )
} ,
send ( opts ) {
2024-01-03 14:23:34 +00:00
let { $messages } = this
2023-12-27 17:25:49 +00:00
opts = { linebreak : true , message : "" , class : [ ] , ... opts }
2024-01-03 14:23:34 +00:00
if ( window . frontend && window . frontend . emit ) window . frontend . emit ( '$chat.send' , opts )
let div = document . createElement ( 'div' )
let msg = document . createElement ( 'div' )
let br = document . createElement ( 'br' )
let nick = document . createElement ( 'div' )
2023-12-27 17:25:49 +00:00
msg . className = "msg"
let html = ` ${ opts . message || '' } ${ opts . html ? opts . html ( opts ) : '' } `
if ( $messages . last == html ) return
msg . innerHTML = html
if ( opts . el ) msg . appendChild ( opts . el )
opts . id = Math . random ( )
if ( opts . class ) {
msg . classList . add . apply ( msg . classList , opts . class )
br . classList . add . apply ( br . classList , opts . class )
2024-01-03 14:23:34 +00:00
div . classList . add . apply ( div . classList , opts . class . concat ( [ "envelope" ] ) )
}
if ( ! opts . from && ! msg . className . match ( /(info|guide)/ ) ) msg . classList . add ( 'self' )
if ( opts . from ) {
nick . className = "user"
nick . innerText = opts . from + ' '
div . appendChild ( nick )
if ( opts . pos ) {
let a = document . createElement ( "a" )
a . href = a . innerText = ` #pos= ${ opts . pos } `
nick . appendChild ( a )
}
2023-12-27 17:25:49 +00:00
}
2023-12-28 09:22:54 +00:00
div . appendChild ( msg )
$messages . appendChild ( div )
if ( opts . linebreak ) div . appendChild ( br )
2023-12-27 17:25:49 +00:00
$messages . scrollTop = $messages . scrollHeight // scroll down
$messages . last = msg . innerHTML
2024-01-03 14:23:34 +00:00
} ,
getChatLog ( ) {
return ( [ ... this . $messages . querySelectorAll ( '.envelope' ) ] )
. filter ( ( d ) => ! d . className . match ( /(info|ui)/ ) )
. map ( ( d ) => d . innerHTML )
. join ( '\n' )
2023-12-27 17:25:49 +00:00
}
} , {
2024-01-03 14:23:34 +00:00
get ( me , k , v ) { return me [ k ] } ,
set ( me , k , v ) {
me [ k ] = v
2023-12-27 17:25:49 +00:00
switch ( k ) {
2024-01-03 14:23:34 +00:00
case "visible" : {
el . style . display = me . visible ? 'block' : 'none'
if ( ! el . inited && ( el . inited = true ) ) me . initListeners ( )
break ;
}
case "visibleChatbar" : {
me . $chatbar . style . display = v ? 'block' : 'none'
}
2023-12-27 17:25:49 +00:00
}
}
} )
}
// reactify component!
document . addEventListener ( '$menu:ready' , ( opts ) => {
opts = opts . detail
document . head . innerHTML += chatComponent . css
2024-01-03 14:23:34 +00:00
window . $chat = document . createElement ( 'div' )
2023-12-27 17:25:49 +00:00
$chat . innerHTML = chatComponent . html
$chat = chatComponent . init ( $chat )
$chat . install ( opts )
//$menu.buttons = ([`<a class="btn" aria-label="button" aria-description="toggle text" id="meeting" onclick="$chat.toggle()">📜 toggle text</a><br>`])
// .concat($menu.buttons)
} )
// alpine component for displaying meetings
chatComponent . css = `
< style type = "text/css" >
# videos {
display : grid - auto - columns ;
grid - column - gap : 5 px ;
margin - bottom : 15 px ;
position : fixed ;
top : 0 ;
left : 0 ;
bottom : 0 ;
right : 0 ;
margin : 15 px ;
z - index : 1500 ;
}
# videos > video {
border - radius : 7 px ;
display : inline - block ;
background : black ;
width : 80 px ;
height : 60 px ;
margin - right : 5 px ;
margin - bottom : 5 px ;
vertical - align : top ;
pointer - events : all ;
}
# videos > video : hover {
filter : brightness ( 1.8 ) ;
cursor : pointer ;
}
# chatbar ,
button # showchat {
z - index : 1500 ;
position : fixed ;
2023-12-27 21:31:42 +00:00
bottom : 24 px ;
height : 34 px ;
2023-12-27 17:25:49 +00:00
left : 20 px ;
width : 48 % ;
background : white ;
padding : 0 px 0 px 0 px 15 px ;
border - radius : 30 px ;
max - width : 500 px ;
box - sizing : border - box ;
box - shadow : 0 px 0 px 5 px 5 px # 0002 ;
}
button # showchat {
z - index : 1550 ;
color : white ;
border : 0 ;
display : none ;
height : 44 px ;
background : # 07 F ;
font - weight : bold ;
}
# chatbar input {
border : none ;
width : 90 % ;
box - sizing : border - box ;
2023-12-27 21:31:42 +00:00
height : 24 px ;
font - size : var ( -- xrf - font - size - 2 ) ;
2023-12-28 09:22:54 +00:00
max - width : unset ;
2023-12-27 17:25:49 +00:00
}
# messages {
position : absolute ;
2024-01-03 14:23:34 +00:00
transition : 1 s ;
top : 0 px ;
2023-12-27 17:25:49 +00:00
left : 0 ;
2024-01-03 14:23:34 +00:00
bottom : 130 px ;
2023-12-27 17:25:49 +00:00
padding : 15 px ;
2024-01-03 14:23:34 +00:00
overflow : hidden ;
pointer - events : none ;
transition : 1 s ;
width : 91 % ;
max - width : 500 px ;
z - index : 100 ;
- webkit - user - select : none ;
- moz - user - select : - moz - none ;
- ms - user - select : none ;
user - select : none ;
}
body . menu # messages {
top : 50 px ;
}
# messages * {
pointer - events : all ;
2023-12-27 17:25:49 +00:00
}
# messages . msg {
2024-01-03 14:23:34 +00:00
transition : all 1 s ease ;
2023-12-27 17:25:49 +00:00
background : # fff ;
display : inline - block ;
2024-01-03 14:23:34 +00:00
padding : 1 px 17 px ;
border - radius : 20 px 0 px 20 px 20 px ;
2023-12-27 17:25:49 +00:00
color : # 000 c ;
margin - bottom : 10 px ;
line - height : 23 px ;
pointer - events : visible ;
line - height : 33 px ;
2024-01-03 14:23:34 +00:00
cursor : grabbing ;
border : 1 px solid # 0002 ;
}
# messages . msg . self {
border - radius : 0 px 20 px 20 px 20 px ;
background : var ( -- xrf - primary ) ;
}
# messages . msg . self ,
# messages . msg . self div {
color : # FFF ;
2023-12-27 17:25:49 +00:00
}
# messages . msg . info {
2024-01-03 14:23:34 +00:00
background : # 473 f7f ;
border - radius : 20 px ;
color : # FFF ;
text - align : right ;
line - height : 19 px ;
}
# messages . msg . info ,
# messages . msg . info * {
font - size : var ( -- xrf - font - size - 0 ) ;
}
# messages . msg a {
text - decoration : underline ;
color : # EEE ;
font - weight : bold ;
transition : 1 s ;
}
# messages . msg a : hover {
color : # FFF ;
}
# messages . msg . ui ,
# messages . msg . ui div {
background : white ;
border : none ;
color : # 333 ;
border - radius : 20 px ;
margin : 0 ;
padding : 0 px 5 px 5 px 5 px ;
2023-12-27 17:25:49 +00:00
}
2023-12-27 18:26:42 +00:00
# messages . guide , . guide {
2023-12-27 17:25:49 +00:00
display : unset ;
}
2023-12-27 18:26:42 +00:00
# messages . guide , . guide {
2023-12-27 17:25:49 +00:00
display : none ;
}
br . guide {
display : inline - block ;
}
# messages . msg . info a : hover ,
# messages button : hover {
filter : brightness ( 1.4 ) ;
}
# messages . msg . multiline {
padding : 2 px 14 px ;
}
# messages button {
text - decoration : none ;
margin : 0 px 15 px 10 px 0 px ;
background : var ( -- xrf - primary ) ;
font - family : var ( -- xrf - font - sans - serif ) ;
color : # FFF ;
border - radius : 7 px ;
padding : 11 px 15 px ;
border : 0 ;
font - weight : bold ;
box - shadow : 0 px 0 px 5 px 5 px # 0002 ;
pointer - events : all ;
}
# messages , # chatbar , # chatbar * , # messages * {
}
2023-12-27 18:26:42 +00:00
# messages button . emoticon ,
# messages . btn . emoticon {
line - height : 2 px ;
width : 20 px ;
display : inline - block ;
padding : 0 px 0 px ;
margin : 0 ;
vertical - align : middle ;
background : none ;
border : none ;
min - width : 31 px ;
box - shadow : none ;
}
# messages button . emoticon : hover ,
# messages . btn . emoticon : hover {
border : 1 px solid # ccc ! important ;
background : # EEE ;
}
2023-12-27 21:31:42 +00:00
. nomargin {
2023-12-27 18:26:42 +00:00
margin : 0 ;
}
2024-01-03 14:23:34 +00:00
. envelope {
height : unset ;
overflow : hidden ;
transition : 1 s ;
}
. user {
margin - left : 13 px ;
font - weight : bold ;
color : var ( -- xrf - dark - gray ) ;
}
. user , . user * {
font - size : var ( -- xrf - font - size - 0 ) ;
}
2023-12-27 17:25:49 +00:00
< / s t y l e > `