| @@ -44,3 +44,22 @@ | |||
| .post .text p:first-child { | |||
| 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; | |||
| } | |||
| @@ -101,31 +101,47 @@ const Post = { | |||
| } | |||
| const ChatConfig = { | |||
| isOn: false, | |||
| toggle() { | |||
| ChatConfig.isOn = !ChatConfig.isOn | |||
| }, | |||
| 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 = { | |||
| 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() { | |||
| return ChatConfig.isOn ? [ | |||
| m('.not-chat', {onclick: () => ChatConfig.isOn = false}), | |||
| m('.chat', | |||
| m('.posts', this.posts.map(post => m(Post, {post}))), | |||
| m('.posts', Chat.posts.map(post => m(Post, {post}))), | |||
| m(TextBox), | |||
| ) | |||
| ] : 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, | |||
| }) | |||
| @@ -2,7 +2,6 @@ const State = Object.seal({ | |||
| username: null, | |||
| websocket: null, | |||
| online: [], | |||
| messages: [], | |||
| get isConnected() { | |||
| return State.websocket && State.websocket.readyState === 1 | |||
| }, | |||
| @@ -21,7 +20,6 @@ const listen = (kind, handler) => { | |||
| } | |||
| listen('login', ({detail}) => { | |||
| State.username = detail.value | |||
| State.messages = [] | |||
| }) | |||
| listen('logout', ({detail}) => { | |||
| State.online = [] | |||
| @@ -32,18 +30,6 @@ listen('state', ({detail}) => { | |||
| Object.assign(State, detail) | |||
| }) | |||
| 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 | |||
| @@ -148,7 +134,6 @@ const Base = { | |||
| ), | |||
| State.isConnected ? [ | |||
| m('button', {onclick: Base.sendLogout}, 'pick name'), | |||
| m('button', {onclick: () => navigator.clipboard.writeText(location)}, 'copy url'), | |||
| ] : null, | |||
| State.isConnected ? m(VideoConfig) : null, | |||
| State.isConnected ? m(ChatConfig) : null, | |||