.post .text p:first-child { | .post .text p:first-child { | ||||
display: inline; | display: inline; | ||||
} | } | ||||
.badge { | |||||
display: inline-flex; | |||||
justify-content: center; | |||||
align-items: center; | |||||
color: white; | |||||
background-color: silver; | |||||
border: none; | |||||
border-radius: 5px; | |||||
font-family: verdana; | |||||
font-size: xx-small; | |||||
font-weight: bold; | |||||
min-width: 15px; | |||||
padding: 0 3px; | |||||
margin: 3px 3px; | |||||
line-height: 1.5; | |||||
} | |||||
.badge.on { | |||||
background-color: crimson; | |||||
} |
} | } | ||||
const ChatConfig = { | const ChatConfig = { | ||||
isOn: false, | isOn: false, | ||||
toggle() { | |||||
ChatConfig.isOn = !ChatConfig.isOn | |||||
}, | |||||
view() { | view() { | ||||
return m('button', {onclick: () => {ChatConfig.isOn = !ChatConfig.isOn}}, 'chat') | |||||
} | |||||
const on = Chat.unseenCount ? '.on' : '' | |||||
return m('button', {onclick: this.toggle}, 'chat ', | |||||
m('.badge' + on, Chat.unseenCount), | |||||
) | |||||
}, | |||||
} | } | ||||
const Chat = { | const Chat = { | ||||
posts: [], | posts: [], | ||||
oncreate() { | |||||
listen('post', ({detail}) => { | |||||
this.posts.push(detail) | |||||
m.redraw() | |||||
}) | |||||
listen('logout', () => { | |||||
this.posts = [] | |||||
}) | |||||
marked.setOptions({ | |||||
breaks: true, | |||||
}) | |||||
unseenCount: 0, | |||||
originalTitle: 'pico.chat', | |||||
onupdate: () => { | |||||
if(document.hasFocus() && ChatConfig.isOn) { | |||||
Chat.unseenCount = 0 | |||||
} | |||||
const extra = Chat.unseenCount ? ` (${Chat.unseenCount})` : `` | |||||
document.title = Chat.originalTitle + extra | |||||
}, | }, | ||||
view() { | view() { | ||||
return ChatConfig.isOn ? [ | return ChatConfig.isOn ? [ | ||||
m('.not-chat', {onclick: () => ChatConfig.isOn = false}), | m('.not-chat', {onclick: () => ChatConfig.isOn = false}), | ||||
m('.chat', | m('.chat', | ||||
m('.posts', this.posts.map(post => m(Post, {post}))), | |||||
m('.posts', Chat.posts.map(post => m(Post, {post}))), | |||||
m(TextBox), | m(TextBox), | ||||
) | ) | ||||
] : null | ] : null | ||||
}, | }, | ||||
} | } | ||||
addEventListener('focus', m.redraw) | |||||
addEventListener('post', ({detail}) => { | |||||
Chat.posts.push(detail) | |||||
Chat.unseenCount += !(document.hasFocus() && ChatConfig.isOn) | |||||
m.redraw() | |||||
}) | |||||
addEventListener('logout', () => { | |||||
Chat.posts = [] | |||||
Chat.unseenCount = 0 | |||||
}) | |||||
marked.setOptions({ | |||||
breaks: true, | |||||
}) |
username: null, | username: null, | ||||
websocket: null, | websocket: null, | ||||
online: [], | online: [], | ||||
messages: [], | |||||
get isConnected() { | get isConnected() { | ||||
return State.websocket && State.websocket.readyState === 1 | return State.websocket && State.websocket.readyState === 1 | ||||
}, | }, | ||||
} | } | ||||
listen('login', ({detail}) => { | listen('login', ({detail}) => { | ||||
State.username = detail.value | State.username = detail.value | ||||
State.messages = [] | |||||
}) | }) | ||||
listen('logout', ({detail}) => { | listen('logout', ({detail}) => { | ||||
State.online = [] | State.online = [] | ||||
Object.assign(State, detail) | Object.assign(State, detail) | ||||
}) | }) | ||||
const doNotLog = new Set(['login', 'state', 'post', 'peerInfo', 'join', 'leave']) | const doNotLog = new Set(['login', 'state', 'post', 'peerInfo', 'join', 'leave']) | ||||
/* | |||||
* | |||||
* ALERTS | |||||
* | |||||
*/ | |||||
State.unseen = 0 | |||||
listen('beep', () => {State.unseen += !document.hasFocus(); updateTitle()}) | |||||
listen('focus', () => {State.unseen = 0; updateTitle()}) | |||||
const updateTitle = () => { | |||||
document.title = location.href.split('//')[1] + (State.unseen ? ` (${State.unseen})` : ``) | |||||
} | |||||
/* | /* | ||||
* | * | ||||
* UTILS | * UTILS | ||||
), | ), | ||||
State.isConnected ? [ | State.isConnected ? [ | ||||
m('button', {onclick: Base.sendLogout}, 'pick name'), | m('button', {onclick: Base.sendLogout}, 'pick name'), | ||||
m('button', {onclick: () => navigator.clipboard.writeText(location)}, 'copy url'), | |||||
] : null, | ] : null, | ||||
State.isConnected ? m(VideoConfig) : null, | State.isConnected ? m(VideoConfig) : null, | ||||
State.isConnected ? m(ChatConfig) : null, | State.isConnected ? m(ChatConfig) : null, |