Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/chat UI #47

Merged
merged 9 commits into from
Apr 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading