Skip to content

Commit

Permalink
Feat/chat UI (#47)
Browse files Browse the repository at this point in the history
#35

---------

Signed-off-by: seven <[email protected]>
  • Loading branch information
Blankll authored Apr 14, 2024
1 parent 7a4416e commit d7f90a2
Show file tree
Hide file tree
Showing 11 changed files with 316 additions and 19 deletions.
7 changes: 7 additions & 0 deletions components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,14 @@ export {}
declare module 'vue' {
export interface GlobalComponents {
AppProvider: typeof import('./src/components/AppProvider.vue')['default']
NAvatar: typeof import('naive-ui')['NAvatar']
NButton: typeof import('naive-ui')['NButton']
NButtonGroup: typeof import('naive-ui')['NButtonGroup']
NCard: typeof import('naive-ui')['NCard']
'NCard:': typeof import('naive-ui')['NCard:']
NCardBody: typeof import('naive-ui')['NCardBody']
NCardFooter: typeof import('naive-ui')['NCardFooter']
NCardHeader: typeof import('naive-ui')['NCardHeader']
NConfigProvider: typeof import('naive-ui')['NConfigProvider']
NDialogProvider: typeof import('naive-ui')['NDialogProvider']
NDropdown: typeof import('naive-ui')['NDropdown']
Expand All @@ -35,9 +39,12 @@ declare module 'vue' {
NRadioGroup: typeof import('naive-ui')['NRadioGroup']
NScrollbar: typeof import('naive-ui')['NScrollbar']
NSelect: typeof import('naive-ui')['NSelect']
NSpace: typeof import('naive-ui')['NSpace']
NSplit: typeof import('naive-ui')['NSplit']
NSwitch: typeof import('naive-ui')['NSwitch']
NTabPane: typeof import('naive-ui')['NTabPane']
NTabs: typeof import('naive-ui')['NTabs']
NTag: typeof import('naive-ui')['NTag']
NTooltip: typeof import('naive-ui')['NTooltip']
RouterLink: typeof import('vue-router')['RouterLink']
RouterMain: typeof import('./src/components/RouterMain.vue')['default']
Expand Down
29 changes: 23 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"node-fetch": "^2.7.0",
"pinia": "^2.1.7",
"pinia-plugin-persistedstate": "^3.2.1",
"ulidx": "^2.3.0",
"update-electron-app": "^3.0.0",
"vue": "^3.4.19",
"vue-i18n": "^9.9.1",
Expand Down Expand Up @@ -65,7 +66,7 @@
"eslint-plugin-vue": "^9.21.1",
"husky": "^9.0.11",
"jest": "^29.7.0",
"naive-ui": "^2.37.3",
"naive-ui": "^2.38.1",
"prettier": "^3.2.5",
"sass": "^1.71.0",
"ts-jest": "^29.1.2",
Expand Down
1 change: 1 addition & 0 deletions src/lang/enUS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export const enUS = {
github: 'GitHub',
user: 'User',
setting: 'Setting',
chatBot: 'AI Assistant',
},
setting: {
basic: 'Basic',
Expand Down
1 change: 1 addition & 0 deletions src/lang/zhCN.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export const zhCN = {
github: 'GitHub',
user: '用户',
setting: '设置',
chatBot: 'AI助手',
},
setting: {
basic: '通用设置',
Expand Down
2 changes: 1 addition & 1 deletion src/layout/components/the-aside.vue
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ import { ref, markRaw } from 'vue';
import { useRouter, useRoute } from 'vue-router';
import { DataBase, Folders, LogoGithub, Settings, UserAvatar, ExpandAll } from '@vicons/carbon';
import { useAppStore } from '../../store';
import theAsideIcon from './the-aside-icon.vue';
import TheAsideIcon from './the-aside-icon.vue';
const router = useRouter();
const route = useRoute();
const appStore = useAppStore();
Expand Down
225 changes: 225 additions & 0 deletions src/layout/components/tool-bar-right.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
<template>
<n-card
v-if="chatBot.active"
class="chat-box-container"
:title="$t('aside.chatBot')"
content-class="chat-box-content"
:segmented="{
content: true,
footer: 'segmented',
}"
>
<template #header-extra></template>
<div class="message-list-box">
<n-scrollbar ref="scrollbar" :style="scrollBarStyle">
<div v-for="msg in messages" :key="msg.id">
<div
:class="[
msg.role === ChatMessageRole.USER ? 'message-item-container-user' : '',
'message-item-container',
]"
>
<div class="message-item-header">
<n-icon size="26">
<bot v-if="msg.role === ChatMessageRole.BOT" />
<face-cool v-else />
</n-icon>
<span>{{ msg.role }}</span>
</div>
<div class="message-item-content">
<pre v-text="msg.content"></pre>
</div>
</div>
</div>
</n-scrollbar>
</div>
<template #footer>
<div class="message-box">
<n-input
v-model:value="message"
type="textarea"
:autosize="{
minRows: 3,
}"
placeholder="Type your message here..."
/>
<n-button-group class="message-action-box">
<n-button text>
<template #icon></template>
</n-button>
<n-button text @click="submitMsg">
<template #icon>
<n-icon size="26">
<send-alt />
</n-icon>
</template>
</n-button>
</n-button-group>
</div>
</template>
</n-card>
<div class="tool-bar-right">
<the-aside-icon
v-for="item in smallNavList"
:key="item.id"
:popover-content="$t(`aside.${item.name}`)"
>
<div
class="icon-item"
:class="{ active: item.id === `${selectedItemId}` }"
@click="navClick(item)"
>
<n-icon size="26">
<component :is="item.icon" />
</n-icon>
</div>
</the-aside-icon>
</div>
</template>

<script setup lang="ts">
import { markRaw, ref } from 'vue';
import { ChatBot, SendAlt, Bot, FaceCool } from '@vicons/carbon';
import TheAsideIcon from './the-aside-icon.vue';
import { ChatMessageRole, useChatStore } from '../../store';
const chatStore = useChatStore();
const { sendMessage } = chatStore;
const { messages } = toRefs(chatStore);
const selectedItemId = ref(-1);
const chatBot = ref({ active: false });
const navClick = (item: any) => {
selectedItemId.value = item.id;
if (item.id === 'chat-bot') {
chatBot.value.active = !chatBot.value.active;
}
};
const smallNavList = ref([
{
id: 'chat-bot',
icon: markRaw(ChatBot),
name: 'chatBot',
},
]);
const message = ref(''); // to hold the message
const scrollbar = ref(null);
const submitMsg = async () => {
if (message.value.trim().length < 1) return;
await sendMessage(message.value);
console.log('submitMsg', message.value);
scrollbar.value.scrollTo({ top: 999999 });
message.value = '';
};
const msgBoxHeight = ref(449);
const scrollBarStyle = computed(() => `max-height: ${msgBoxHeight.value}px`);
const updateHeight = () => {
if (chatBot.value.active) {
const chatMsgContent = document.querySelector('.chat-box-container .message-list-box');
msgBoxHeight.value = chatMsgContent.clientHeight;
}
};
onMounted(() => {
window.addEventListener('resize', updateHeight);
updateHeight();
});
onUnmounted(() => {
window.removeEventListener('resize', updateHeight);
});
</script>

<style scoped>
.tool-bar-right {
--aside-width: 40px;
width: var(--aside-width);
box-sizing: border-box;
display: flex;
flex-direction: column;
border-left: 1px solid var(--border-color);
.icon-item {
height: var(--aside-width);
margin: 10px 0;
display: flex;
box-sizing: border-box;
justify-content: center;
align-items: center;
color: var(--text-color);
cursor: pointer;
.n-icon {
opacity: 0.4;
transition: 0.3s;
}
&.active {
position: relative;
.n-icon {
opacity: 1;
}
}
&:hover {
.n-icon {
opacity: 0.9;
}
}
}
}
.chat-box-container {
width: 500px;
.n-card__content {
margin: 0;
padding: 0;
}
.message-list-box {
height: 100%;
padding: 0;
margin: 0;
.message-item-container {
width: 100%;
display: flex;
flex-direction: column;
justify-content: space-around;
padding: 10px;
.message-item-header {
display: flex;
align-items: center;
span {
font-weight: bold;
}
.n-icon {
margin-right: 10px;
}
}
}
.message-item-container-user {
background-color: var(--bg-color);
border-top: 1px solid var(--border-color);
border-bottom: 1px solid var(--border-color);
}
}
.message-box {
background-color: var(--border-color);
.message-action-box {
display: flex;
justify-content: space-between;
height: 20px;
padding: 10px;
}
}
}
</style>
2 changes: 2 additions & 0 deletions src/layout/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@
<div class="right-layout">
<router-main />
</div>
<tool-bar-right />
</div>
</template>

<script setup lang="ts">
import TheAside from './components/the-aside.vue';
import RouterMain from '../components/RouterMain.vue';
import ToolBarRight from './components/tool-bar-right.vue';
</script>

<style lang="scss" scoped>
Expand Down
Loading

0 comments on commit d7f90a2

Please sign in to comment.