mirror of
https://github.com/m1k1o/neko.git
synced 2024-07-24 14:40:50 +12:00
Merge branch 'dev' into add-turn-server
This commit is contained in:
commit
7a61f7e2da
@ -40,6 +40,7 @@ For n.eko room management software visit https://github.com/m1k1o/neko-rooms.
|
|||||||
- Added simple language picker.
|
- Added simple language picker.
|
||||||
- Added `?usr=<display-name>` that will prefill username. This allows creating auto-join links.
|
- Added `?usr=<display-name>` that will prefill username. This allows creating auto-join links.
|
||||||
- Added `?cast=1` that will hide all control and show only video.
|
- Added `?cast=1` that will hide all control and show only video.
|
||||||
|
- Shake keyboard icon if someone attempted to control when is nobody hosting.
|
||||||
- Support for password protected `NEKO_ICESERVERS` (by @mbattista).
|
- Support for password protected `NEKO_ICESERVERS` (by @mbattista).
|
||||||
|
|
||||||
### Bugs
|
### Bugs
|
||||||
@ -67,6 +68,7 @@ For n.eko room management software visit https://github.com/m1k1o/neko-rooms.
|
|||||||
- Abiltiy to include neko as a component in another Vue.Js project (by @gbrian).
|
- Abiltiy to include neko as a component in another Vue.Js project (by @gbrian).
|
||||||
- Added HEALTHCHECK to Dockerfile.
|
- Added HEALTHCHECK to Dockerfile.
|
||||||
- Arguments in broadcast pipeline are optional, not positional and can be repeated `{url} {device} {display}`.
|
- Arguments in broadcast pipeline are optional, not positional and can be repeated `{url} {device} {display}`.
|
||||||
|
- Chat messages are dense, when repeated, they are joined together.
|
||||||
|
|
||||||
### Roadmap & TODOs
|
### Roadmap & TODOs
|
||||||
- Catch errors from gst pipeline, tell user if broadcast failed.
|
- Catch errors from gst pipeline, tell user if broadcast failed.
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
"axios": "^0.21.1",
|
"axios": "^0.21.1",
|
||||||
"date-fns": "^2.16.1",
|
"date-fns": "^2.16.1",
|
||||||
"emoji-datasource": "^6.0.1",
|
"emoji-datasource": "^6.0.1",
|
||||||
"emojilib": "^3.0.1",
|
|
||||||
"eventemitter3": "^4.0.7",
|
"eventemitter3": "^4.0.7",
|
||||||
"resize-observer-polyfill": "^1.5.1",
|
"resize-observer-polyfill": "^1.5.1",
|
||||||
"simple-markdown": "^0.7.2",
|
"simple-markdown": "^0.7.2",
|
||||||
@ -56,6 +55,7 @@
|
|||||||
"@vue/eslint-config-prettier": "^6.0.0",
|
"@vue/eslint-config-prettier": "^6.0.0",
|
||||||
"@vue/eslint-config-typescript": "^7.0.0",
|
"@vue/eslint-config-typescript": "^7.0.0",
|
||||||
"core-js": "^3.9.1",
|
"core-js": "^3.9.1",
|
||||||
|
"emojilib": "^2.4.0",
|
||||||
"eslint": "^6.8.0",
|
"eslint": "^6.8.0",
|
||||||
"eslint-plugin-prettier": "^3.1.4",
|
"eslint-plugin-prettier": "^3.1.4",
|
||||||
"eslint-plugin-vue": "^7.8.0",
|
"eslint-plugin-vue": "^7.8.0",
|
||||||
|
File diff suppressed because one or more lines are too long
@ -9,7 +9,7 @@
|
|||||||
<neko-header />
|
<neko-header />
|
||||||
</div>
|
</div>
|
||||||
<div class="video-container">
|
<div class="video-container">
|
||||||
<neko-video ref="video" :hideControls="hideControls" />
|
<neko-video ref="video" :hideControls="hideControls" @control-attempt="controlAttempt" />
|
||||||
</div>
|
</div>
|
||||||
<div v-if="!hideControls" class="room-container">
|
<div v-if="!hideControls" class="room-container">
|
||||||
<neko-members />
|
<neko-members />
|
||||||
@ -18,7 +18,7 @@
|
|||||||
<neko-menu />
|
<neko-menu />
|
||||||
</div>
|
</div>
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<neko-controls />
|
<neko-controls :shakeKbd="shakeKbd" />
|
||||||
</div>
|
</div>
|
||||||
<div class="emotes">
|
<div class="emotes">
|
||||||
<neko-emotes />
|
<neko-emotes />
|
||||||
@ -174,6 +174,8 @@
|
|||||||
export default class extends Vue {
|
export default class extends Vue {
|
||||||
@Ref('video') video!: Video
|
@Ref('video') video!: Video
|
||||||
|
|
||||||
|
shakeKbd = false
|
||||||
|
|
||||||
get hideControls() {
|
get hideControls() {
|
||||||
return !!new URL(location.href).searchParams.get('cast')
|
return !!new URL(location.href).searchParams.get('cast')
|
||||||
}
|
}
|
||||||
@ -184,6 +186,13 @@
|
|||||||
this.$accessor.settings.setSound(false)
|
this.$accessor.settings.setSound(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
controlAttempt() {
|
||||||
|
if (this.shakeKbd || this.$accessor.remote.hosted) return
|
||||||
|
|
||||||
|
this.shakeKbd = true
|
||||||
|
setTimeout(() => (this.shakeKbd = false), 5000)
|
||||||
|
}
|
||||||
|
|
||||||
get about() {
|
get about() {
|
||||||
return this.$accessor.client.about
|
return this.$accessor.client.about
|
||||||
}
|
}
|
||||||
|
3518
client/src/assets/styles/vendor/_emoji.scss
vendored
3518
client/src/assets/styles/vendor/_emoji.scss
vendored
File diff suppressed because it is too large
Load Diff
@ -2,7 +2,14 @@
|
|||||||
<div class="chat">
|
<div class="chat">
|
||||||
<ul class="chat-history" ref="history" @click="onClick">
|
<ul class="chat-history" ref="history" @click="onClick">
|
||||||
<template v-for="(message, index) in history">
|
<template v-for="(message, index) in history">
|
||||||
<li :key="index" class="message" v-if="message.type === 'text'">
|
<li
|
||||||
|
:key="index"
|
||||||
|
class="message"
|
||||||
|
v-if="message.type === 'text'"
|
||||||
|
:class="{
|
||||||
|
bulk: index > 0 && history[index - 1].id == message.id && history[index - 1].type === 'text',
|
||||||
|
}"
|
||||||
|
>
|
||||||
<div class="author" @contextmenu.stop.prevent="onContext($event, { member: member(message.id) })">
|
<div class="author" @contextmenu.stop.prevent="onContext($event, { member: member(message.id) })">
|
||||||
<neko-avatar class="avatar" :seed="member(message.id).displayname" :size="40" />
|
<neko-avatar class="avatar" :seed="member(message.id).displayname" :size="40" />
|
||||||
</div>
|
</div>
|
||||||
@ -94,6 +101,7 @@
|
|||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
|
|
||||||
&.message {
|
&.message {
|
||||||
|
padding-top: 15px;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
|
|
||||||
.author {
|
.author {
|
||||||
@ -104,7 +112,7 @@
|
|||||||
height: 40px;
|
height: 40px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: $style-primary;
|
background: $style-primary;
|
||||||
margin: 0px 10px 10px 0px;
|
margin-right: 10px;
|
||||||
|
|
||||||
.avatar {
|
.avatar {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -219,6 +227,19 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.bulk {
|
||||||
|
padding-top: 0px;
|
||||||
|
|
||||||
|
.author {
|
||||||
|
visibility: hidden;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-head {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.event {
|
&.event {
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
<li v-if="!isTouch">
|
<li v-if="!isTouch">
|
||||||
<i
|
<i
|
||||||
:class="[
|
:class="[
|
||||||
|
shakeKbd ? 'shake' : '',
|
||||||
hosted && !hosting ? 'disabled' : '',
|
hosted && !hosting ? 'disabled' : '',
|
||||||
!hosted && !hosting ? 'faded' : '',
|
!hosted && !hosting ? 'faded' : '',
|
||||||
'fas',
|
'fas',
|
||||||
@ -53,6 +54,46 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
.shake {
|
||||||
|
animation: shake 1.25s cubic-bezier(0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes shake {
|
||||||
|
0% {
|
||||||
|
transform: scale(1) translate(0px, 0) rotate(0);
|
||||||
|
}
|
||||||
|
10% {
|
||||||
|
transform: scale(1.25) translate(-2px, -2px) rotate(-20deg);
|
||||||
|
}
|
||||||
|
20% {
|
||||||
|
transform: scale(1.5) translate(4px, -4px) rotate(20deg);
|
||||||
|
}
|
||||||
|
30% {
|
||||||
|
transform: scale(1.75) translate(-4px, -6px) rotate(-20deg);
|
||||||
|
}
|
||||||
|
40% {
|
||||||
|
transform: scale(2) translate(6px, -8px) rotate(20deg);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: scale(2.25) translate(-6px, -10px) rotate(-20deg);
|
||||||
|
}
|
||||||
|
60% {
|
||||||
|
transform: scale(2) translate(6px, -8px) rotate(20deg);
|
||||||
|
}
|
||||||
|
70% {
|
||||||
|
transform: scale(1.75) translate(-4px, -6px) rotate(-20deg);
|
||||||
|
}
|
||||||
|
80% {
|
||||||
|
transform: scale(1.5) translate(4px, -4px) rotate(20deg);
|
||||||
|
}
|
||||||
|
90% {
|
||||||
|
transform: scale(1.25) translate(-2px, -2px) rotate(-20deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: scale(1) translate(0px, 0) rotate(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
@ -195,10 +236,12 @@
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Vue, Component } from 'vue-property-decorator'
|
import { Vue, Component, Prop } from 'vue-property-decorator'
|
||||||
|
|
||||||
@Component({ name: 'neko-controls' })
|
@Component({ name: 'neko-controls' })
|
||||||
export default class extends Vue {
|
export default class extends Vue {
|
||||||
|
@Prop(Boolean) readonly shakeKbd = false
|
||||||
|
|
||||||
get isTouch() {
|
get isTouch() {
|
||||||
return (
|
return (
|
||||||
(typeof navigator.maxTouchPoints !== 'undefined' ? navigator.maxTouchPoints < 0 : false) ||
|
(typeof navigator.maxTouchPoints !== 'undefined' ? navigator.maxTouchPoints < 0 : false) ||
|
||||||
|
@ -15,8 +15,8 @@
|
|||||||
? $t('room.unlock')
|
? $t('room.unlock')
|
||||||
: $t('room.lock')
|
: $t('room.lock')
|
||||||
: locked
|
: locked
|
||||||
? $t('room.unlocked')
|
? $t('room.locked')
|
||||||
: $t('room.locked'),
|
: $t('room.unlocked'),
|
||||||
placement: 'bottom',
|
placement: 'bottom',
|
||||||
offset: 5,
|
offset: 5,
|
||||||
boundariesElement: 'body',
|
boundariesElement: 'body',
|
||||||
|
@ -552,9 +552,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMouseDown(e: MouseEvent) {
|
onMouseDown(e: MouseEvent) {
|
||||||
|
if (!this.hosting) {
|
||||||
|
this.$emit('control-attempt', e)
|
||||||
|
}
|
||||||
|
|
||||||
if (!this.hosting || this.locked) {
|
if (!this.hosting || this.locked) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.onMousePos(e)
|
this.onMousePos(e)
|
||||||
this.$client.sendData('mousedown', { key: e.button + 1 })
|
this.$client.sendData('mousedown', { key: e.button + 1 })
|
||||||
}
|
}
|
||||||
@ -563,6 +568,7 @@
|
|||||||
if (!this.hosting || this.locked) {
|
if (!this.hosting || this.locked) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.onMousePos(e)
|
this.onMousePos(e)
|
||||||
this.$client.sendData('mouseup', { key: e.button + 1 })
|
this.$client.sendData('mouseup', { key: e.button + 1 })
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ interface Emoji {
|
|||||||
category: string
|
category: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const SHEET_COLUMNS = 57
|
const SHEET_COLUMNS = 58
|
||||||
const MULTIPLY = 100 / (SHEET_COLUMNS - 1)
|
const MULTIPLY = 100 / (SHEET_COLUMNS - 1)
|
||||||
|
|
||||||
const css: string[] = []
|
const css: string[] = []
|
||||||
|
Loading…
Reference in New Issue
Block a user