feat: Add a back to bottom button to the chat page(#2957)
parent
1fb280aa3d
commit
0c53e31b2a
|
|
@ -3,8 +3,10 @@
|
||||||
<div class="text-center mb-8" v-if="loading">
|
<div class="text-center mb-8" v-if="loading">
|
||||||
<el-button class="border-primary video-stop-button" @click="stopChat">
|
<el-button class="border-primary video-stop-button" @click="stopChat">
|
||||||
<app-icon iconName="app-video-stop" class="mr-8"></app-icon>
|
<app-icon iconName="app-video-stop" class="mr-8"></app-icon>
|
||||||
{{ $t('chat.operation.stopChat') }}</el-button>
|
{{ $t('chat.operation.stopChat') }}</el-button
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="operate-textarea">
|
<div class="operate-textarea">
|
||||||
<el-scrollbar max-height="136">
|
<el-scrollbar max-height="136">
|
||||||
<div
|
<div
|
||||||
|
|
@ -332,7 +334,7 @@ const props = withDefaults(
|
||||||
available: true,
|
available: true,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
const emit = defineEmits(['update:chatId', 'update:loading', 'update:showUserInput'])
|
const emit = defineEmits(['update:chatId', 'update:loading', 'update:showUserInput', 'backBottom'])
|
||||||
const chartOpenId = ref<string>()
|
const chartOpenId = ref<string>()
|
||||||
const chatId_context = computed({
|
const chatId_context = computed({
|
||||||
get: () => {
|
get: () => {
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,12 @@
|
||||||
position: relative;
|
position: relative;
|
||||||
color: var(--app-text-color);
|
color: var(--app-text-color);
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
.back-bottom-button {
|
||||||
|
position: absolute;
|
||||||
|
right: 14px;
|
||||||
|
top: -30px;
|
||||||
|
}
|
||||||
&__content {
|
&__content {
|
||||||
padding-top: 0;
|
padding-top: 0;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|
@ -16,7 +22,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
|
|
||||||
:deep(ol) {
|
:deep(ol) {
|
||||||
margin-left: 16px !important;
|
margin-left: 16px !important;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -66,35 +66,39 @@
|
||||||
</TransitionContent>
|
</TransitionContent>
|
||||||
</div>
|
</div>
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
|
<div style="position: relative">
|
||||||
<ChatInputOperate
|
<!-- 置底按钮 -->
|
||||||
:app-id="appId"
|
<el-button v-if="isBottom" circle class="back-bottom-button" @click="setScrollBottom">
|
||||||
:application-details="applicationDetails"
|
<el-icon><ArrowDownBold /></el-icon>
|
||||||
:is-mobile="isMobile"
|
</el-button>
|
||||||
:type="type"
|
<ChatInputOperate
|
||||||
:send-message="sendMessage"
|
:app-id="appId"
|
||||||
:open-chat-id="openChatId"
|
:application-details="applicationDetails"
|
||||||
:validate="validate"
|
:is-mobile="isMobile"
|
||||||
:chat-management="ChatManagement"
|
:type="type"
|
||||||
v-model:chat-id="chartOpenId"
|
:send-message="sendMessage"
|
||||||
v-model:loading="loading"
|
:open-chat-id="openChatId"
|
||||||
v-model:show-user-input="showUserInput"
|
:validate="validate"
|
||||||
v-if="type !== 'log'"
|
:chat-management="ChatManagement"
|
||||||
>
|
v-model:chat-id="chartOpenId"
|
||||||
<template #userInput>
|
v-model:loading="loading"
|
||||||
<el-button
|
v-model:show-user-input="showUserInput"
|
||||||
v-if="isUserInput || isAPIInput"
|
v-if="type !== 'log'"
|
||||||
class="user-input-button mb-8"
|
>
|
||||||
@click="toggleUserInput"
|
<template #userInput>
|
||||||
>
|
<el-button
|
||||||
<AppIcon iconName="app-edit" :size="16" class="mr-4"></AppIcon>
|
v-if="isUserInput || isAPIInput"
|
||||||
<span class="ellipsis">
|
class="user-input-button mb-8"
|
||||||
{{ userInputTitle || $t('chat.userInput') }}
|
@click="toggleUserInput"
|
||||||
</span>
|
>
|
||||||
</el-button>
|
<AppIcon iconName="app-edit" :size="16" class="mr-4"></AppIcon>
|
||||||
</template>
|
<span class="ellipsis">
|
||||||
</ChatInputOperate>
|
{{ userInputTitle || $t('chat.userInput') }}
|
||||||
|
</span>
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</ChatInputOperate>
|
||||||
|
</div>
|
||||||
<Control></Control>
|
<Control></Control>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -603,10 +607,12 @@ function chatMessage(chat?: any, problem?: string, re_chat?: boolean, other_para
|
||||||
const scrollTop = ref(0)
|
const scrollTop = ref(0)
|
||||||
|
|
||||||
const scorll = ref(true)
|
const scorll = ref(true)
|
||||||
|
const isBottom = ref(false)
|
||||||
|
|
||||||
const getMaxHeight = () => {
|
const getMaxHeight = () => {
|
||||||
return dialogScrollbar.value!.scrollHeight
|
return dialogScrollbar.value!.scrollHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 滚动滚动条到最上面
|
* 滚动滚动条到最上面
|
||||||
* @param $event
|
* @param $event
|
||||||
|
|
@ -621,6 +627,8 @@ const handleScrollTop = ($event: any) => {
|
||||||
} else {
|
} else {
|
||||||
scorll.value = false
|
scorll.value = false
|
||||||
}
|
}
|
||||||
|
isBottom.value =
|
||||||
|
scrollTop.value + scrollDiv.value.wrapRef.offsetHeight < dialogScrollbar.value!.scrollHeight
|
||||||
emit('scroll', { ...$event, dialogScrollbar: dialogScrollbar.value, scrollDiv: scrollDiv.value })
|
emit('scroll', { ...$event, dialogScrollbar: dialogScrollbar.value, scrollDiv: scrollDiv.value })
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@
|
||||||
<el-pagination
|
<el-pagination
|
||||||
v-model:current-page="paginationConfig.current_page"
|
v-model:current-page="paginationConfig.current_page"
|
||||||
v-model:page-size="paginationConfig.page_size"
|
v-model:page-size="paginationConfig.page_size"
|
||||||
:page-sizes="pageSizes"
|
:page-sizes="paginationConfig.page_sizes|| pageSizes"
|
||||||
:total="paginationConfig.total"
|
:total="paginationConfig.total"
|
||||||
layout="total, prev, pager, next, sizes"
|
layout="total, prev, pager, next, sizes"
|
||||||
@size-change="handleSizeChange"
|
@size-change="handleSizeChange"
|
||||||
|
|
|
||||||
|
|
@ -290,6 +290,11 @@
|
||||||
height: 20px;
|
height: 20px;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
}
|
}
|
||||||
|
.el-tag--plain.el-tag--info {
|
||||||
|
color: var(--app-text-color-secondary);
|
||||||
|
font-weight: 500;
|
||||||
|
border-color: var(--app-text-color-light-1);
|
||||||
|
}
|
||||||
|
|
||||||
// el-select
|
// el-select
|
||||||
.el-select__selected-item {
|
.el-select__selected-item {
|
||||||
|
|
|
||||||
|
|
@ -207,6 +207,7 @@ const paginationConfig = reactive({
|
||||||
current_page: 1,
|
current_page: 1,
|
||||||
page_size: 10,
|
page_size: 10,
|
||||||
total: 0,
|
total: 0,
|
||||||
|
page_sizes: [10, 20, 50, 100, 1000],
|
||||||
})
|
})
|
||||||
|
|
||||||
const filterText = ref('')
|
const filterText = ref('')
|
||||||
|
|
|
||||||
|
|
@ -179,7 +179,7 @@
|
||||||
<template #title>
|
<template #title>
|
||||||
<div>
|
<div>
|
||||||
{{ item.name }}
|
{{ item.name }}
|
||||||
<el-tag v-if="item.version" class="ml-4">
|
<el-tag v-if="item.version" class="ml-4" type="info" effect="plain">
|
||||||
{{ item.version }}
|
{{ item.version }}
|
||||||
</el-tag>
|
</el-tag>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,29 @@
|
||||||
<template>
|
<template>
|
||||||
<CardBox :title="props.tool.name" :description="props.tool.desc" class="cursor">
|
<CardBox :title="props.tool.name" :description="props.tool.desc" class="cursor">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<el-avatar v-if="isAppIcon(props.tool?.icon)" shape="square" :size="32" style="background: none">
|
<el-avatar
|
||||||
|
v-if="isAppIcon(props.tool?.icon)"
|
||||||
|
shape="square"
|
||||||
|
:size="32"
|
||||||
|
style="background: none"
|
||||||
|
>
|
||||||
<img :src="resetUrl(props.tool?.icon)" alt="" />
|
<img :src="resetUrl(props.tool?.icon)" alt="" />
|
||||||
</el-avatar>
|
</el-avatar>
|
||||||
<el-avatar v-else-if="props.tool?.name" :name="props.tool?.name" pinyinColor shape="square" :size="32" />
|
<el-avatar
|
||||||
|
v-else-if="props.tool?.name"
|
||||||
|
:name="props.tool?.name"
|
||||||
|
pinyinColor
|
||||||
|
shape="square"
|
||||||
|
:size="32"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template #title>
|
||||||
|
<div>
|
||||||
|
{{ props.tool?.name }}
|
||||||
|
<el-tag v-if="props.tool?.version" class="ml-4" type="info" effect="plain">
|
||||||
|
{{ props.tool?.version }}
|
||||||
|
</el-tag>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #subTitle>
|
<template #subTitle>
|
||||||
<el-text class="color-secondary" size="small">
|
<el-text class="color-secondary" size="small">
|
||||||
|
|
@ -29,24 +48,24 @@
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import {isAppIcon, resetUrl} from '@/utils/common'
|
import { isAppIcon, resetUrl } from '@/utils/common'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
tool: any,
|
tool: any
|
||||||
getSubTitle: (v: any) => string
|
getSubTitle: (v: any) => string
|
||||||
addLoading: boolean
|
addLoading: boolean
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'handleAdd'): void;
|
(e: 'handleAdd'): void
|
||||||
(e: 'handleDetail'): void;
|
(e: 'handleDetail'): void
|
||||||
}>();
|
}>()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.el-card {
|
.el-card {
|
||||||
:deep(.card-footer) {
|
:deep(.card-footer) {
|
||||||
&>div:first-of-type {
|
& > div:first-of-type {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,34 @@
|
||||||
<template>
|
<template>
|
||||||
<el-dialog v-model="dialogVisible" width="1000" append-to-body class="tool-store-dialog" align-center
|
<el-dialog
|
||||||
:close-on-click-modal="false" :close-on-press-escape="false">
|
v-model="dialogVisible"
|
||||||
|
width="1000"
|
||||||
|
append-to-body
|
||||||
|
class="tool-store-dialog"
|
||||||
|
align-center
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
:close-on-press-escape="false"
|
||||||
|
>
|
||||||
<template #header="{ titleId }">
|
<template #header="{ titleId }">
|
||||||
<div class="dialog-header flex-between mb-8">
|
<div class="dialog-header flex-between mb-8">
|
||||||
<h4 :id="titleId" class="medium">
|
<h4 :id="titleId" class="medium">
|
||||||
{{ $t('views.tool.toolStore.title') }}
|
{{ $t('views.tool.toolStore.title') }}
|
||||||
</h4>
|
</h4>
|
||||||
<el-radio-group v-model="toolType" @change="radioChange" class="app-radio-button-group">
|
<el-radio-group v-model="toolType" @change="radioChange" class="app-radio-button-group">
|
||||||
<el-radio-button value="INTERNAL">{{ $t('views.tool.toolStore.internal') }}</el-radio-button>
|
<el-radio-button value="INTERNAL">{{
|
||||||
|
$t('views.tool.toolStore.internal')
|
||||||
|
}}</el-radio-button>
|
||||||
<el-radio-button value="APPSTORE">{{ $t('views.tool.toolStore.title') }}</el-radio-button>
|
<el-radio-button value="APPSTORE">{{ $t('views.tool.toolStore.title') }}</el-radio-button>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
|
|
||||||
<div class="flex align-center" style="margin-right: 28px;">
|
<div class="flex align-center" style="margin-right: 28px">
|
||||||
<el-input v-model="searchValue" :placeholder="$t('common.search')" prefix-icon="Search" class="w-240 mr-8"
|
<el-input
|
||||||
clearable @change="getList" />
|
v-model="searchValue"
|
||||||
|
:placeholder="$t('common.search')"
|
||||||
|
prefix-icon="Search"
|
||||||
|
class="w-240 mr-8"
|
||||||
|
clearable
|
||||||
|
@change="getList"
|
||||||
|
/>
|
||||||
<el-divider direction="vertical" />
|
<el-divider direction="vertical" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -21,23 +36,40 @@
|
||||||
|
|
||||||
<LayoutContainer v-loading="loading">
|
<LayoutContainer v-loading="loading">
|
||||||
<template #left>
|
<template #left>
|
||||||
<el-anchor direction="vertical" :offset="130" type="default" container=".category-scrollbar"
|
<el-anchor
|
||||||
@click="handleClick">
|
direction="vertical"
|
||||||
<el-anchor-link v-for="category in categories" :key="category.id" :href="`#category-${category.id}`"
|
:offset="130"
|
||||||
:title="category.title" />
|
type="default"
|
||||||
|
container=".category-scrollbar"
|
||||||
|
@click="handleClick"
|
||||||
|
>
|
||||||
|
<el-anchor-link
|
||||||
|
v-for="category in categories"
|
||||||
|
:key="category.id"
|
||||||
|
:href="`#category-${category.id}`"
|
||||||
|
:title="category.title"
|
||||||
|
/>
|
||||||
</el-anchor>
|
</el-anchor>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-scrollbar class="layout-bg" wrap-class="p-16-24 category-scrollbar">
|
<el-scrollbar class="layout-bg" wrap-class="p-16-24 category-scrollbar">
|
||||||
<template v-if="filterList === null">
|
<template v-if="filterList === null">
|
||||||
<div v-for="category in categories" :key="category.id">
|
<div v-for="category in categories" :key="category.id">
|
||||||
<h4 class="title-decoration-1 mb-16 mt-8 color-text-primary" :id="`category-${category.id}`">
|
<h4
|
||||||
|
class="title-decoration-1 mb-16 mt-8 color-text-primary"
|
||||||
|
:id="`category-${category.id}`"
|
||||||
|
>
|
||||||
{{ category.title }}
|
{{ category.title }}
|
||||||
</h4>
|
</h4>
|
||||||
<el-row :gutter="16">
|
<el-row :gutter="16">
|
||||||
<el-col v-for="tool in category.tools" :key="tool.id" :span="12" class="mb-16">
|
<el-col v-for="tool in category.tools" :key="tool.id" :span="12" class="mb-16">
|
||||||
<ToolCard :tool="tool" :addLoading="addLoading" :get-sub-title="getSubTitle"
|
<ToolCard
|
||||||
@handleAdd="handleOpenAdd(tool)" @handleDetail="handleDetail(tool)" />
|
:tool="tool"
|
||||||
|
:addLoading="addLoading"
|
||||||
|
:get-sub-title="getSubTitle"
|
||||||
|
@handleAdd="handleOpenAdd(tool)"
|
||||||
|
@handleDetail="handleDetail(tool)"
|
||||||
|
/>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -49,8 +81,13 @@
|
||||||
</h4>
|
</h4>
|
||||||
<el-row :gutter="16" v-if="filterList.length">
|
<el-row :gutter="16" v-if="filterList.length">
|
||||||
<el-col v-for="tool in filterList" :key="tool.id" :span="12" class="mb-16">
|
<el-col v-for="tool in filterList" :key="tool.id" :span="12" class="mb-16">
|
||||||
<ToolCard :tool="tool" :addLoading="addLoading" :get-sub-title="getSubTitle"
|
<ToolCard
|
||||||
@handleAdd="handleOpenAdd(tool)" @handleDetail="handleDetail(tool)" />
|
:tool="tool"
|
||||||
|
:addLoading="addLoading"
|
||||||
|
:get-sub-title="getSubTitle"
|
||||||
|
@handleAdd="handleOpenAdd(tool)"
|
||||||
|
@handleDetail="handleDetail(tool)"
|
||||||
|
/>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-empty v-else :description="$t('common.noData')" />
|
<el-empty v-else :description="$t('common.noData')" />
|
||||||
|
|
@ -70,7 +107,7 @@ import ToolCard from './ToolCard.vue'
|
||||||
import { MsgSuccess } from '@/utils/message'
|
import { MsgSuccess } from '@/utils/message'
|
||||||
import InternalDescDrawer from './InternalDescDrawer.vue'
|
import InternalDescDrawer from './InternalDescDrawer.vue'
|
||||||
import AddInternalToolDialog from './AddInternalToolDialog.vue'
|
import AddInternalToolDialog from './AddInternalToolDialog.vue'
|
||||||
import { loadSharedApi } from "@/utils/dynamics-api/shared-api.ts";
|
import { loadSharedApi } from '@/utils/dynamics-api/shared-api.ts'
|
||||||
import useStore from '@/stores'
|
import useStore from '@/stores'
|
||||||
const { user } = useStore()
|
const { user } = useStore()
|
||||||
interface ToolCategory {
|
interface ToolCategory {
|
||||||
|
|
@ -81,7 +118,7 @@ interface ToolCategory {
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
apiType: {
|
apiType: {
|
||||||
type: String as () => 'workspace' | 'systemShare' | 'systemManage',
|
type: String as () => 'workspace' | 'systemShare' | 'systemManage',
|
||||||
default: 'workspace'
|
default: 'workspace',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
const emit = defineEmits(['refresh'])
|
const emit = defineEmits(['refresh'])
|
||||||
|
|
@ -102,12 +139,12 @@ const categories = ref<ToolCategory[]>([
|
||||||
{
|
{
|
||||||
id: 'web_search',
|
id: 'web_search',
|
||||||
title: t('views.tool.toolStore.webSearch'),
|
title: t('views.tool.toolStore.webSearch'),
|
||||||
tools: []
|
tools: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'database_search',
|
id: 'database_search',
|
||||||
title: t('views.tool.toolStore.databaseQuery'),
|
title: t('views.tool.toolStore.databaseQuery'),
|
||||||
tools: []
|
tools: [],
|
||||||
},
|
},
|
||||||
// {
|
// {
|
||||||
// id: 'image',
|
// id: 'image',
|
||||||
|
|
@ -128,7 +165,7 @@ const categories = ref<ToolCategory[]>([
|
||||||
const filterList = ref<any>(null)
|
const filterList = ref<any>(null)
|
||||||
|
|
||||||
function getSubTitle(tool: any) {
|
function getSubTitle(tool: any) {
|
||||||
return categories.value.find(i => i.id === tool.label)?.title ?? ''
|
return categories.value.find((i) => i.id === tool.label)?.title ?? ''
|
||||||
}
|
}
|
||||||
|
|
||||||
function open(id: string) {
|
function open(id: string) {
|
||||||
|
|
@ -156,7 +193,7 @@ async function getInternalToolList() {
|
||||||
filterList.value = res.data
|
filterList.value = res.data
|
||||||
} else {
|
} else {
|
||||||
filterList.value = null
|
filterList.value = null
|
||||||
categories.value.forEach(category => {
|
categories.value.forEach((category) => {
|
||||||
// if (category.id === 'recommend') {
|
// if (category.id === 'recommend') {
|
||||||
// category.tools = res.data
|
// category.tools = res.data
|
||||||
// } else {
|
// } else {
|
||||||
|
|
@ -183,7 +220,7 @@ async function getStoreToolList() {
|
||||||
categories.value = tags.map((tag: any) => ({
|
categories.value = tags.map((tag: any) => ({
|
||||||
id: tag.key,
|
id: tag.key,
|
||||||
title: tag.name, // 国际化
|
title: tag.name, // 国际化
|
||||||
tools: storeTools.filter((tool: any) => tool.label === tag.key)
|
tools: storeTools.filter((tool: any) => tool.label === tag.key),
|
||||||
}))
|
}))
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
|
|
@ -244,7 +281,7 @@ async function handleStoreAdd(tool: any) {
|
||||||
download_callback_url: tool.downloadCallbackUrl,
|
download_callback_url: tool.downloadCallbackUrl,
|
||||||
icon: tool.icon,
|
icon: tool.icon,
|
||||||
versions: tool.versions,
|
versions: tool.versions,
|
||||||
label: tool.label
|
label: tool.label,
|
||||||
}
|
}
|
||||||
await loadSharedApi({ type: 'tool', systemType: props.apiType })
|
await loadSharedApi({ type: 'tool', systemType: props.apiType })
|
||||||
.addStoreTool(tool.id, obj, addLoading)
|
.addStoreTool(tool.id, obj, addLoading)
|
||||||
|
|
@ -268,6 +305,9 @@ defineExpose({ open })
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.tool-store-dialog {
|
.tool-store-dialog {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
.el-dialog__headerbtn {
|
||||||
|
top: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
.el-dialog__header {
|
.el-dialog__header {
|
||||||
padding: 12px 20px 4px 24px;
|
padding: 12px 20px 4px 24px;
|
||||||
|
|
@ -314,7 +354,6 @@ defineExpose({ open })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.category-scrollbar {
|
.category-scrollbar {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue