| right: 0; | right: 0; | ||||
| top: 0; | top: 0; | ||||
| } | } | ||||
| .not-chat { | |||||
| z-index: 999; | |||||
| background-color: rgba(0, 0, 0, 0.8); | |||||
| position: fixed; | |||||
| height: 100vh; | |||||
| width: 100vw; | |||||
| right: 0; | |||||
| top: 0; | |||||
| } | |||||
| .chat .actions { | .chat .actions { | ||||
| display: grid; | display: grid; | ||||
| grid-template-columns: 1fr auto; | grid-template-columns: 1fr auto; | ||||
| margin: 3px 3px; | margin: 3px 3px; | ||||
| line-height: 1.5; | line-height: 1.5; | ||||
| } | } | ||||
| .badge.on { | |||||
| .badge.hot { | |||||
| background-color: crimson; | background-color: crimson; | ||||
| } | } |
| } | } | ||||
| } | } | ||||
| const ChatConfig = { | const ChatConfig = { | ||||
| isOn: false, | |||||
| toggle() { | |||||
| ChatConfig.isOn = !ChatConfig.isOn | |||||
| }, | |||||
| view() { | view() { | ||||
| const on = Chat.unseenCount ? '.on' : '' | |||||
| return m('button', {onclick: this.toggle}, 'chat ', | |||||
| m('.badge' + on, Chat.unseenCount), | |||||
| const onclick = () => {Chat.isOn = !Chat.isOn} | |||||
| const hot = Chat.unseenCount ? '.hot' : '' | |||||
| return m('button', {onclick}, 'chat ', | |||||
| m('.badge' + hot, Chat.unseenCount), | |||||
| ) | ) | ||||
| }, | }, | ||||
| } | } | ||||
| unseenCount: 0, | unseenCount: 0, | ||||
| originalTitle: 'pico.chat', | originalTitle: 'pico.chat', | ||||
| onupdate: () => { | onupdate: () => { | ||||
| if(document.hasFocus() && ChatConfig.isOn) { | |||||
| if(document.hasFocus() && Chat.isOn) { | |||||
| Chat.unseenCount = 0 | Chat.unseenCount = 0 | ||||
| textbox.focus() | |||||
| } | } | ||||
| const extra = Chat.unseenCount ? ` (${Chat.unseenCount})` : `` | const extra = Chat.unseenCount ? ` (${Chat.unseenCount})` : `` | ||||
| document.title = Chat.originalTitle + extra | document.title = Chat.originalTitle + extra | ||||
| }, | }, | ||||
| view() { | view() { | ||||
| return ChatConfig.isOn ? [ | |||||
| m('.not-chat', {onclick: () => ChatConfig.isOn = false}), | |||||
| m('.chat', | |||||
| m('.posts', Chat.posts.map(post => m(Post, {post}))), | |||||
| m(TextBox), | |||||
| ) | |||||
| ] : null | |||||
| return m('.chat', | |||||
| m('.posts', Chat.posts.map(post => m(Post, {post}))), | |||||
| m(TextBox), | |||||
| ) | |||||
| }, | }, | ||||
| } | } | ||||
| addEventListener('focus', m.redraw) | addEventListener('focus', m.redraw) |
| const VolumeMap = { | const VolumeMap = { | ||||
| isOn: false, | |||||
| size: 200, | size: 200, | ||||
| positions: new Map(), | positions: new Map(), | ||||
| toggle() { | |||||
| VolumeMap.isOn = !VolumeMap.isOn | |||||
| }, | |||||
| onremove() { | onremove() { | ||||
| VolumeMap.positions.clear() | VolumeMap.positions.clear() | ||||
| }, | }, |
| * BASE | * BASE | ||||
| * | * | ||||
| */ | */ | ||||
| const Shadow = { | |||||
| oncreate({dom, attrs}) { | |||||
| dom.listener = () => attrs.app.isOn = !attrs.app.isOn | |||||
| addEventListener(attrs.key, dom.listener) | |||||
| }, | |||||
| onremove({dom, attrs}) { | |||||
| removeEventListener(attrs.key, dom.listener) | |||||
| }, | |||||
| view({attrs}) { | |||||
| const style = { | |||||
| zIndex: 999, | |||||
| backgroundColor: 'rgba(0, 0, 0, 0.8)', | |||||
| visibility: attrs.app.isOn ? 'unset' : 'hidden', | |||||
| position: 'fixed', | |||||
| height: '100vh', | |||||
| width: '100vw', | |||||
| right: 0, | |||||
| top: 0, | |||||
| } | |||||
| const onclick = ({target: {classList}}) => { | |||||
| classList.contains('shadow') && signal({kind: attrs.key}) | |||||
| } | |||||
| return m('.shadow', {style, onclick}, m(attrs.app)) | |||||
| }, | |||||
| } | |||||
| const Settings = { | const Settings = { | ||||
| get(key) { | get(key) { | ||||
| try { | try { | ||||
| m('button', {onclick: Base.sendLogout}, 'settings'), | m('button', {onclick: Base.sendLogout}, 'settings'), | ||||
| m(VideoConfig), | m(VideoConfig), | ||||
| m(ChatConfig), | m(ChatConfig), | ||||
| m('button', {onclick: VolumeMap.toggle}, 'volume'), | |||||
| ] : [ | ] : [ | ||||
| m('form.login', | m('form.login', | ||||
| {onsubmit: Base.sendLogin}, | {onsubmit: Base.sendLogin}, | ||||
| m('span.error', State.info), | m('span.error', State.info), | ||||
| ), | ), | ||||
| State.isConnected ? [ | State.isConnected ? [ | ||||
| m(StreamContainer), | |||||
| m(Chat), | |||||
| params.get('map') === 'true' ? m(VolumeMap) : null, | |||||
| m(StreamContainer, {key: 'lolo'}), | |||||
| m(Shadow, {key: 'chat-shadow', app: Chat}), | |||||
| m(Shadow, {key: 'map-shadow', app: VolumeMap}), | |||||
| ] : m(Settings), | ] : m(Settings), | ||||
| ) | ) | ||||
| }, | }, |