Skip to content

Commit

Permalink
feat(overlays): chat directions (#484)
Browse files Browse the repository at this point in the history
  • Loading branch information
crashmax-dev authored Dec 17, 2023
1 parent acb0c71 commit f4bcc08
Show file tree
Hide file tree
Showing 19 changed files with 286 additions and 92 deletions.
4 changes: 2 additions & 2 deletions apps/api/internal/impl_protected/overlays/chat.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ func (c *Overlays) chatOverlayDbToGrpc(s model.ChatOverlaySettings) *overlays_ch
FontFamily: s.FontFamily,
ShowBadges: s.ShowBadges,
ShowAnnounceBadge: s.ShowAnnounceBadge,
ReverseMessages: s.ReverseMessages,
TextShadowColor: s.TextShadowColor,
TextShadowSize: s.TextShadowSize,
ChatBackgroundColor: s.ChatBackgroundColor,
Direction: s.Direction,
}
}

Expand All @@ -43,10 +43,10 @@ func (c *Overlays) chatOverlayGrpcToDb(s *overlays_chat.Settings) model.ChatOver
FontFamily: s.FontFamily,
ShowBadges: s.ShowBadges,
ShowAnnounceBadge: s.ShowAnnounceBadge,
ReverseMessages: s.ReverseMessages,
TextShadowColor: s.TextShadowColor,
TextShadowSize: s.TextShadowSize,
ChatBackgroundColor: s.ChatBackgroundColor,
Direction: s.Direction,
}
}

Expand Down
2 changes: 1 addition & 1 deletion frontend/dashboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"@twir/grpc": "workspace:^",
"@types/lodash.chunk": "^4.2.9",
"@vueuse/components": "^10.7.0",
"@vueuse/core": "^10.7.0",
"@vueuse/core": "10.7.0",
"date-fns": "^2.30.0",
"grid-layout-plus": "^1.0.3",
"kappagen": "^0.3.5",
Expand Down
8 changes: 6 additions & 2 deletions frontend/dashboard/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -365,10 +365,14 @@
"fontFamilyDescription": "We use Google fonts, you can find any font there with your prefered variant (i.e cyrillic)",
"showBadges": "Show badges",
"showAnnounceBadge": "Show announce badge (only for boxed style)",
"reverseMessages": "Show new messages on top, instead bottom",
"resetToDefault": "Reset to default",
"textShadow": "Text shadow",
"backgroundColor": "Background color"
"backgroundColor": "Background color",
"direction": "Direction of message display",
"directionTop": "Top",
"directionBottom": "Bottom",
"directionLeft": "Left",
"directionRight": "Right"
},
"kappagen": {
"description": "Liven up your screen with explosions, movements, fireworks, walls of emoticons",
Expand Down
8 changes: 6 additions & 2 deletions frontend/dashboard/src/locales/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -351,13 +351,17 @@
"fontFamily": "Шрифт",
"showBadges": "Отображать значки",
"showAnnounceBadge": "Отображать значок объявления (только для рамочного стиля)",
"reverseMessages": "Отображать новые сообщения сверху, а не снизу",
"description": "Встраивание оверлея чата в Ваше ПО для проведения прямых трансляций",
"hideCommands": "Скрывать команды, не отображать сообщения начинающиеся с \"!\"",
"fontSize": "Размер шрифта",
"resetToDefault": "Сбросить настройки",
"textShadow": "Тень от текста",
"backgroundColor": "Цвет фона"
"backgroundColor": "Цвет фона",
"direction": "Направление отображения сообщений",
"directionTop": "Сверху",
"directionBottom": "Снизу",
"directionLeft": "Слева",
"directionRight": "Справа"
},
"kappagen": {
"description": "Оживите свой экран взрывами, движениями, фейерверками, стенами смайликов",
Expand Down
34 changes: 24 additions & 10 deletions frontend/dashboard/src/pages/overlays/chat/Chat.vue
Original file line number Diff line number Diff line change
Expand Up @@ -98,14 +98,23 @@ const defaultSettings: Settings = {
fontFamily: defaultFont,
showBadges: true,
showAnnounceBadge: true,
reverseMessages: false,
textShadowColor: 'rgba(0,0,0,1)',
textShadowSize: 0,
chatBackgroundColor: 'rgba(0, 0, 0, 0)',
direction: 'top',
};
const formValue = ref<Settings>(structuredClone(defaultSettings));
const directionOptions = computed(() => {
return [
{ label: t('overlays.chat.directionTop'), value: 'top' },
{ label: t('overlays.chat.directionRight'), value: 'right' },
{ label: t('overlays.chat.directionBottom'), value: 'bottom' },
{ label: t('overlays.chat.directionLeft'), value: 'left' },
];
});
const chatBoxSettings = computed<ChatBoxSettings>(() => {
return {
channelId: '',
Expand Down Expand Up @@ -205,32 +214,32 @@ const canCopyLink = computed(() => {
<n-select v-model:value="formValue.preset" :options="styleSelectOptions" />
</div>

<div class="switch">
<n-switch v-model:value="formValue.hideBots" />
<span>{{ t('overlays.chat.hideBots') }}</span>
<div>
<span>{{ t('overlays.chat.direction') }}</span>
<n-select v-model:value="formValue.direction" :options="directionOptions" />
</div>

<div class="switch">
<n-switch v-model:value="formValue.hideCommands" />
<span>{{ t('overlays.chat.hideCommands') }}</span>
<span>{{ t('overlays.chat.hideBots') }}</span>
<n-switch v-model:value="formValue.hideBots" />
</div>

<div class="switch">
<n-switch v-model:value="formValue.reverseMessages" />
<span>{{ t('overlays.chat.reverseMessages') }}</span>
<span>{{ t('overlays.chat.hideCommands') }}</span>
<n-switch v-model:value="formValue.hideCommands" />
</div>

<div class="switch">
<n-switch v-model:value="formValue.showBadges" />
<span>{{ t('overlays.chat.showBadges') }}</span>
<n-switch v-model:value="formValue.showBadges" />
</div>

<div v-if="formValue.preset === 'boxed'" class="switch">
<span>{{ t('overlays.chat.showAnnounceBadge') }}</span>
<n-switch
v-model:value="formValue.showAnnounceBadge"
:disabled="!formValue.showBadges"
/>
<span>{{ t('overlays.chat.showAnnounceBadge') }}</span>
</div>

<n-divider />
Expand Down Expand Up @@ -339,6 +348,11 @@ const canCopyLink = computed(() => {
background-color: v-bind('themeVars.cardColor');
}
.switch {
display: flex;
justify-content: space-between;
}
:deep(.chat) {
height: 80dvh;
}
Expand Down
2 changes: 1 addition & 1 deletion frontend/overlays/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"@protobuf-ts/twirp-transport": "2.9.3",
"@twir/frontend-chat": "workspace:^",
"@twir/grpc": "workspace:^",
"@vueuse/core": "10.6.1",
"@vueuse/core": "10.7.0",
"emoji-regex": "10.3.0",
"kappagen": "0.3.5",
"nested-css-to-flat": "1.0.5",
Expand Down
2 changes: 1 addition & 1 deletion frontend/overlays/src/pages/overlays/chat.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const route = useRoute();
const apiKey = route.params.apiKey as string;
const messages = ref<Message[]>([]);
const maxMessages = ref(100);
const maxMessages = ref(30);
const { settings } = useChatOverlaySocket(apiKey);
Expand Down
2 changes: 1 addition & 1 deletion frontend/overlays/src/sockets/chat_overlay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ export const useChatOverlaySocket = (apiKey: string): { settings: Ref<Settings>
fontFamily: 'Roboto',
showAnnounceBadge: true,
showBadges: true,
reverseMessages: false,
textShadowColor: '',
textShadowSize: 0,
chatBackgroundColor: '',
direction: 'top',
});

const { data, send } = useWebSocket(
Expand Down
2 changes: 1 addition & 1 deletion frontend/public-page/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"@tanstack/vue-table": "8.10.7",
"@twir/grpc": "workspace:^",
"@vueuse/components": "10.6.1",
"@vueuse/core": "10.6.1",
"@vueuse/core": "10.7.0",
"vue": "3.3.9",
"vue-router": "4.2.5"
},
Expand Down
1 change: 1 addition & 0 deletions libs/frontend-chat/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"preview": "vite preview"
},
"dependencies": {
"@vueuse/core": "10.7.0",
"vue": "3.3.9"
},
"devDependencies": {
Expand Down
122 changes: 87 additions & 35 deletions libs/frontend-chat/src/chatBox.vue
Original file line number Diff line number Diff line change
@@ -1,37 +1,81 @@
<script setup lang="ts">
import { useWindowSize } from '@vueuse/core';
import { computed, nextTick, ref, toValue, watch } from 'vue';
import { getChatDirection } from './helpers.js';
import ChatMessageStyleBoxed from './styles/boxed.vue';
import ChatMessageStyleClean from './styles/clean.vue';
import type { Message, Settings } from './types.js';
const chatElement = ref<HTMLDivElement>();
const props = defineProps<{
messages: Message[]
settings: Settings
}>();
const chatMessages = ref<HTMLDivElement>();
watch(() => props.messages.length, async () => {
if (props.settings.reverseMessages) return;
await nextTick();
scrollToBottom();
scrollByDirection(props.settings.direction);
});
watch(() => props.settings.direction, (direction) => {
scrollByDirection(direction);
});
function scrollToBottom() {
chatElement.value?.scrollIntoView(false);
if (!chatMessages.value) return;
chatMessages.value.scrollIntoView(true);
}
function scrollToTop() {
chatElement.value?.scrollIntoView(true);
if (!chatMessages.value) return;
chatMessages.value.scrollIntoView(false);
}
watch(() => props.settings.reverseMessages, (newValue) => {
if (newValue) {
scrollToTop();
} else {
function scrollToLeft() {
if (!chatMessages.value) return;
chatMessages.value.scrollLeft += 999999;
}
function scrollToRight() {
if (!chatMessages.value) return;
chatMessages.value.scrollLeft -= 999999;
}
function scrollByDirection(direction: string) {
if (direction === 'bottom') {
scrollToBottom();
}
if (direction === 'top') {
scrollToTop();
}
if (direction === 'left') {
scrollToLeft();
}
if (direction === 'right') {
scrollToRight();
}
}
const chatDirection = computed(() => getChatDirection(props.settings.direction));
const messagesFlexDirection = computed(() => {
switch (props.settings.direction) {
case 'top':
return 'column';
case 'bottom':
return 'column-reverse';
case 'left':
return 'row';
case 'right':
return 'row-reverse';
default:
return 'column';
}
});
const chatMessageComponent = computed(() => {
Expand All @@ -44,8 +88,16 @@ const chatMessageComponent = computed(() => {
}
});
const fontSize = computed(() => `${props.settings.fontSize}px`);
const { height } = useWindowSize();
const windowHeight = computed(() => {
if (getChatDirection(props.settings.direction) === 'horizontal') {
return `${height.value}px`;
}
return 'auto';
});
const fontSize = computed(() => `${props.settings.fontSize}px`);
const defaultFont = 'Roboto';
const fontFamily = computed(() => {
try {
Expand All @@ -59,56 +111,56 @@ const fontFamily = computed(() => {
const fontUrl = computed(() => {
return `https://fonts.googleapis.com/css?family=${fontFamily.value}`;
});
const messagesDirection = computed(() => {
return props.settings.reverseMessages ? 'column-reverse' : 'column';
});
</script>

<template>
<div ref="chatElement" class="chat">
<div class="chat">
<component :is="'style'">
@import url('{{ fontUrl }}')
</component>
<TransitionGroup name="list" tag="div" class="messages">
<component
:is="chatMessageComponent"
v-for="msg of messages"
:key="msg.internalId"
:msg="msg"
:settings="toValue(settings)"
/>
</TransitionGroup>
<div ref="chatMessages" class="messages">
<TransitionGroup name="list">
<component
:is="chatMessageComponent"
v-for="msg of messages"
:key="msg.internalId"
:msg="msg"
:direction="chatDirection"
:settings="toValue(settings)"
/>
</TransitionGroup>
</div>
</div>
</template>

<style>
.chat {
height: 100dvh;
width: 100%;
color: #fff;
font-size: v-bind(fontSize);
height: 100vh;
width: 100%;
color: #fff;
font-size: v-bind(fontSize);
font-family: v-bind(fontFamily);
overflow: hidden;
position: relative;
background-color: v-bind('settings.chatBackgroundColor');
}
.chat .messages {
.messages {
display: flex;
flex-direction: v-bind(messagesDirection);
flex-direction: v-bind(messagesFlexDirection);
gap: 8px;
overflow: hidden;
padding-bottom: 5px;
height: v-bind(windowHeight);
}
.list-enter-active,
.list-leave-active {
transition: all 0.5s ease;
transition: all 0.5s ease;
}
.list-enter-from,
.list-leave-to {
opacity: 0;
transform: translateX(-30px);
opacity: 0;
transform: translateX(-30px);
}
</style>
Loading

0 comments on commit f4bcc08

Please sign in to comment.