Demo:顶部工具栏支持根据窗口宽度自动收起到更多中

This commit is contained in:
wanglin2 2023-10-16 14:26:10 +08:00
parent 20157fcc8d
commit 83b916d3c9
5 changed files with 465 additions and 284 deletions

View File

@ -197,8 +197,8 @@ export default {
toolbar: { toolbar: {
undo: 'Undo', undo: 'Undo',
redo: 'Redo', redo: 'Redo',
insertSiblingNode: 'Insert sibling node', insertSiblingNode: 'Sibling node',
insertChildNode: 'Insert child node', insertChildNode: 'Child node',
deleteNode: 'Delete node', deleteNode: 'Delete node',
image: 'Image', image: 'Image',
icon: 'Icon', icon: 'Icon',
@ -218,7 +218,8 @@ export default {
shortcutKey: 'Shortcut key', shortcutKey: 'Shortcut key',
associativeLine: 'Associative line', associativeLine: 'Associative line',
painter: 'Painter', painter: 'Painter',
formula: 'Formula' formula: 'Formula',
more: 'More'
}, },
edit: { edit: {
newFeatureNoticeTitle: 'New feature reminder', newFeatureNoticeTitle: 'New feature reminder',

View File

@ -195,8 +195,8 @@ export default {
toolbar: { toolbar: {
undo: '回退', undo: '回退',
redo: '前进', redo: '前进',
insertSiblingNode: '插入同级节点', insertSiblingNode: '同级节点',
insertChildNode: '插入子节点', insertChildNode: '子节点',
deleteNode: '删除节点', deleteNode: '删除节点',
image: '图片', image: '图片',
icon: '图标', icon: '图标',
@ -216,7 +216,8 @@ export default {
shortcutKey: '快捷键', shortcutKey: '快捷键',
associativeLine: '关联线', associativeLine: '关联线',
painter: '格式刷', painter: '格式刷',
formula: '公式' formula: '公式',
more: '更多'
}, },
edit: { edit: {
newFeatureNoticeTitle: '新特性提醒', newFeatureNoticeTitle: '新特性提醒',

View File

@ -145,6 +145,7 @@ export default {
onLangChange(lang) { onLangChange(lang) {
i18n.locale = lang i18n.locale = lang
storeLang(lang) storeLang(lang)
this.$bus.$emit('lang_change')
}, },
showSearch() { showSearch() {

View File

@ -1,149 +1,28 @@
<template> <template>
<div class="toolbarContainer" :class="{ isDark: isDark }"> <div class="toolbarContainer" :class="{ isDark: isDark }">
<div class="toolbar"> <div class="toolbar" ref="toolbarRef">
<!-- 节点操作 --> <!-- 节点操作 -->
<div class="toolbarBlock"> <div class="toolbarBlock">
<div <ToolbarNodeBtnList :list="horizontalList"></ToolbarNodeBtnList>
class="toolbarBtn" <!-- 更多 -->
:class="{ <el-popover
disabled: readonly || backEnd v-model="popoverShow"
}" placement="bottom-end"
@click="$bus.$emit('execCommand', 'BACK')" width="120"
trigger="hover"
v-if="showMoreBtn"
style="margin-left: 20px;"
> >
<span class="icon iconfont iconhoutui-shi"></span> <ToolbarNodeBtnList
<span class="text">{{ $t('toolbar.undo') }}</span> dir="v"
</div> :list="verticalList"
<div @click.native="popoverShow = false"
class="toolbarBtn" ></ToolbarNodeBtnList>
:class="{ <div slot="reference" class="toolbarBtn">
disabled: readonly || forwardEnd <span class="icon iconfont icongongshi"></span>
}" <span class="text">{{ $t('toolbar.more') }}</span>
@click="$bus.$emit('execCommand', 'FORWARD')" </div>
> </el-popover>
<span class="icon iconfont iconqianjin1"></span>
<span class="text">{{ $t('toolbar.redo') }}</span>
</div>
<div
class="toolbarBtn"
:class="{
disabled: activeNodes.length <= 0 || hasGeneralization,
active: isInPainter
}"
@click="$bus.$emit('startPainter')"
>
<span class="icon iconfont iconjiedian"></span>
<span class="text">{{ $t('toolbar.painter') }}</span>
</div>
<div
class="toolbarBtn"
:class="{
disabled: activeNodes.length <= 0 || hasRoot || hasGeneralization
}"
@click="$bus.$emit('execCommand', 'INSERT_NODE')"
>
<span class="icon iconfont iconjiedian"></span>
<span class="text">{{ $t('toolbar.insertSiblingNode') }}</span>
</div>
<div
class="toolbarBtn"
:class="{
disabled: activeNodes.length <= 0 || hasGeneralization
}"
@click="$bus.$emit('execCommand', 'INSERT_CHILD_NODE')"
>
<span class="icon iconfont icontianjiazijiedian"></span>
<span class="text">{{ $t('toolbar.insertChildNode') }}</span>
</div>
<div
class="toolbarBtn"
:class="{
disabled: activeNodes.length <= 0
}"
@click="$bus.$emit('execCommand', 'REMOVE_NODE')"
>
<span class="icon iconfont iconshanchu"></span>
<span class="text">{{ $t('toolbar.deleteNode') }}</span>
</div>
<div
class="toolbarBtn"
:class="{
disabled: activeNodes.length <= 0
}"
@click="$bus.$emit('showNodeImage')"
>
<span class="icon iconfont iconimage"></span>
<span class="text">{{ $t('toolbar.image') }}</span>
</div>
<div
class="toolbarBtn"
:class="{
disabled: activeNodes.length <= 0
}"
@click="showNodeIcon"
>
<span class="icon iconfont iconxiaolian"></span>
<span class="text">{{ $t('toolbar.icon') }}</span>
</div>
<div
class="toolbarBtn"
:class="{
disabled: activeNodes.length <= 0
}"
@click="$bus.$emit('showNodeLink')"
>
<span class="icon iconfont iconchaolianjie"></span>
<span class="text">{{ $t('toolbar.link') }}</span>
</div>
<div
class="toolbarBtn"
:class="{
disabled: activeNodes.length <= 0
}"
@click="$bus.$emit('showNodeNote')"
>
<span class="icon iconfont iconflow-Mark"></span>
<span class="text">{{ $t('toolbar.note') }}</span>
</div>
<div
class="toolbarBtn"
:class="{
disabled: activeNodes.length <= 0
}"
@click="$bus.$emit('showNodeTag')"
>
<span class="icon iconfont iconbiaoqian"></span>
<span class="text">{{ $t('toolbar.tag') }}</span>
</div>
<div
class="toolbarBtn"
:class="{
disabled: activeNodes.length <= 0 || hasRoot || hasGeneralization
}"
@click="$bus.$emit('execCommand', 'ADD_GENERALIZATION')"
>
<span class="icon iconfont icongaikuozonglan"></span>
<span class="text">{{ $t('toolbar.summary') }}</span>
</div>
<div
class="toolbarBtn"
:class="{
disabled: activeNodes.length <= 0 || hasGeneralization
}"
@click="$bus.$emit('createAssociativeLine')"
>
<span class="icon iconfont iconlianjiexian"></span>
<span class="text">{{ $t('toolbar.associativeLine') }}</span>
</div>
<div
class="toolbarBtn"
:class="{
disabled: activeNodes.length <= 0 || hasGeneralization
}"
@click="showFormula"
>
<span class="icon iconfont icongongshi"></span>
<span class="text">{{ $t('toolbar.formula') }}</span>
</div>
</div> </div>
<!-- 导出 --> <!-- 导出 -->
<div class="toolbarBlock"> <div class="toolbarBlock">
@ -187,10 +66,12 @@ import NodeNote from './NodeNote'
import NodeTag from './NodeTag' import NodeTag from './NodeTag'
import Export from './Export' import Export from './Export'
import Import from './Import' import Import from './Import'
import { mapState, mapMutations } from 'vuex' import { mapState } from 'vuex'
import { Notification } from 'element-ui' import { Notification } from 'element-ui'
import exampleData from 'simple-mind-map/example/exampleData' import exampleData from 'simple-mind-map/example/exampleData'
import { getData } from '../../../api' import { getData } from '../../../api'
import ToolbarNodeBtnList from './ToolbarNodeBtnList.vue'
import { throttle } from 'simple-mind-map/src/utils/index'
/** /**
* @Author: 王林 * @Author: 王林
@ -207,35 +88,35 @@ export default {
NodeNote, NodeNote,
NodeTag, NodeTag,
Export, Export,
Import Import,
ToolbarNodeBtnList
}, },
data() { data() {
return { return {
activeNodes: [], list: [
backEnd: false, 'back',
forwardEnd: true, 'forward',
readonly: false, 'painter',
isFullDataFile: false, 'siblingNode',
timer: null, 'childNode',
isInPainter: false 'deleteNode',
'image',
'icon',
'link',
'note',
'tag',
'summary',
'associativeLine',
'formula'
],
horizontalList: [],
verticalList: [],
showMoreBtn: true,
popoverShow: false
} }
}, },
computed: { computed: {
...mapState(['isHandleLocalFile', 'isDark']), ...mapState(['isHandleLocalFile', 'isDark'])
hasRoot() {
return (
this.activeNodes.findIndex(node => {
return node.isRoot
}) !== -1
)
},
hasGeneralization() {
return (
this.activeNodes.findIndex(node => {
return node.isGeneralization
}) !== -1
)
}
}, },
watch: { watch: {
isHandleLocalFile(val) { isHandleLocalFile(val) {
@ -245,68 +126,48 @@ export default {
} }
}, },
created() { created() {
this.$bus.$on('mode_change', this.onModeChange)
this.$bus.$on('node_active', this.onNodeActive)
this.$bus.$on('back_forward', this.onBackForward)
this.$bus.$on('write_local_file', this.onWriteLocalFile) this.$bus.$on('write_local_file', this.onWriteLocalFile)
this.$bus.$on('painter_start', this.onPainterStart) },
this.$bus.$on('painter_end', this.onPainterEnd) mounted() {
this.computeToolbarShow()
this.computeToolbarShowThrottle = throttle(this.computeToolbarShow, 300)
window.addEventListener('resize', this.computeToolbarShowThrottle)
this.$bus.$on('lang_change', this.computeToolbarShowThrottle)
}, },
beforeDestroy() { beforeDestroy() {
this.$bus.$off('mode_change', this.onModeChange)
this.$bus.$off('node_active', this.onNodeActive)
this.$bus.$off('back_forward', this.onBackForward)
this.$bus.$off('write_local_file', this.onWriteLocalFile) this.$bus.$off('write_local_file', this.onWriteLocalFile)
this.$bus.$off('painter_start', this.onPainterStart) window.removeEventListener('resize', this.computeToolbarShowThrottle)
this.$bus.$off('painter_end', this.onPainterEnd) this.$bus.$off('lang_change', this.computeToolbarShowThrottle)
}, },
methods: { methods: {
...mapMutations(['setActiveSidebar']), //
computeToolbarShow() {
showNodeIcon() { const windowWidth = window.innerWidth - 40
// this.$bus.$emit('showNodeIcon') const all = [...this.list]
this.$bus.$emit('close_node_icon_toolbar') let index = 1
this.setActiveSidebar('nodeIconSidebar') const loopCheck = () => {
if (index > all.length) return done()
this.horizontalList = all.slice(0, index)
this.$nextTick(() => {
const width = this.$refs.toolbarRef.getBoundingClientRect().width
if (width < windowWidth) {
index++
loopCheck()
} else if (index > 0 && width > windowWidth) {
index--
this.horizontalList = all.slice(0, index)
done()
}
})
}
const done = () => {
this.verticalList = all.slice(index)
this.showMoreBtn = this.verticalList.length > 0
}
loopCheck()
}, },
// //
showFormula() {
this.setActiveSidebar('formulaSidebar')
},
/**
* @Author: 王林25
* @Date: 2022-11-14 19:17:40
* @Desc: 监听模式切换
*/
onModeChange(mode) {
this.readonly = mode === 'readonly'
},
/**
* @Author: 王林25
* @Date: 2022-11-14 19:18:06
* @Desc: 监听节点激活
*/
onNodeActive(...args) {
this.activeNodes = [...args[1]]
},
/**
* @Author: 王林25
* @Date: 2022-11-14 19:18:31
* @Desc: 监听前进后退
*/
onBackForward(index, len) {
this.backEnd = index <= 0
this.forwardEnd = index >= len - 1
},
/**
* @Author: 王林25
* @Date: 2022-11-14 19:19:14
* @Desc: 监听本地文件读写
*/
onWriteLocalFile(content) { onWriteLocalFile(content) {
clearTimeout(this.timer) clearTimeout(this.timer)
this.timer = setTimeout(() => { this.timer = setTimeout(() => {
@ -314,11 +175,7 @@ export default {
}, 1000) }, 1000)
}, },
/** //
* @Author: 王林
* @Date: 2022-09-24 15:40:09
* @Desc: 打开本地文件
*/
async openLocalFile() { async openLocalFile() {
try { try {
let [_fileHandle] = await window.showOpenFilePicker({ let [_fileHandle] = await window.showOpenFilePicker({
@ -353,11 +210,7 @@ export default {
} }
}, },
/** //
* @Author: 王林
* @Date: 2022-09-24 15:40:18
* @Desc: 读取本地文件
*/
async readFile() { async readFile() {
let file = await fileHandle.getFile() let file = await fileHandle.getFile()
let fileReader = new FileReader() let fileReader = new FileReader()
@ -375,11 +228,7 @@ export default {
fileReader.readAsText(file) fileReader.readAsText(file)
}, },
/** //
* @Author: 王林
* @Date: 2022-09-24 15:40:26
* @Desc: 渲染读取的数据
*/
setData(str) { setData(str) {
try { try {
let data = JSON.parse(str) let data = JSON.parse(str)
@ -402,11 +251,7 @@ export default {
} }
}, },
/** //
* @Author: 王林
* @Date: 2022-09-24 15:40:42
* @Desc: 写入本地文件
*/
async writeLocalFile(content) { async writeLocalFile(content) {
if (!fileHandle || !this.isHandleLocalFile) { if (!fileHandle || !this.isHandleLocalFile) {
return return
@ -420,30 +265,18 @@ export default {
await writable.close() await writable.close()
}, },
/** //
* @Author: 王林
* @Date: 2022-09-24 15:40:48
* @Desc: 创建本地文件
*/
async createNewLocalFile() { async createNewLocalFile() {
await this.createLocalFile(exampleData) await this.createLocalFile(exampleData)
}, },
/** //
* @Author: 王林
* @Date: 2022-09-24 15:49:17
* @Desc: 另存为
*/
async saveLocalFile() { async saveLocalFile() {
let data = getData() let data = getData()
await this.createLocalFile(data) await this.createLocalFile(data)
}, },
/** //
* @Author: 王林
* @Date: 2022-09-24 15:50:22
* @Desc: 创建本地文件
*/
async createLocalFile(content) { async createLocalFile(content) {
try { try {
let _fileHandle = await window.showSaveFilePicker({ let _fileHandle = await window.showSaveFilePicker({
@ -479,14 +312,6 @@ export default {
'你的浏览器可能不支持建议使用最新版本的Chrome浏览器' '你的浏览器可能不支持建议使用最新版本的Chrome浏览器'
) )
} }
},
onPainterStart() {
this.isInPainter = true
},
onPainterEnd() {
this.isInPainter = false
} }
} }
} }
@ -496,7 +321,7 @@ export default {
.toolbarContainer { .toolbarContainer {
&.isDark { &.isDark {
.toolbar { .toolbar {
color: hsla(0,0%,100%,.9); color: hsla(0, 0%, 100%, 0.9);
.toolbarBlock { .toolbarBlock {
background-color: #262a2e; background-color: #262a2e;
} }
@ -510,7 +335,7 @@ export default {
&:hover { &:hover {
&:not(.disabled) { &:not(.disabled) {
.icon { .icon {
background: hsla(0,0%,100%,.05); background: hsla(0, 0%, 100%, 0.05);
} }
} }
} }
@ -527,14 +352,12 @@ export default {
transform: translateX(-50%); transform: translateX(-50%);
top: 20px; top: 20px;
width: max-content; width: max-content;
max-width: 100%;
display: flex; display: flex;
font-size: 12px; font-size: 12px;
font-family: PingFangSC-Regular, PingFang SC; font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400; font-weight: 400;
color: rgba(26, 26, 26, 0.8); color: rgba(26, 26, 26, 0.8);
z-index: 2; z-index: 2;
overflow-x: auto;
.toolbarBlock { .toolbarBlock {
display: flex; display: flex;
@ -600,16 +423,4 @@ export default {
} }
} }
} }
@media screen and (max-width: 1040px) {
.toolbarContainer {
.toolbar {
left: 20px;
right: 20px;
transform: translateX(0);
width: auto;
max-width: none;
}
}
}
</style> </style>

View File

@ -0,0 +1,367 @@
<template>
<div class="toolbarNodeBtnList" :class="[dir, { isDark: isDark }]">
<template v-for="item in list">
<div
v-if="item === 'back'"
class="toolbarBtn"
:class="{
disabled: readonly || backEnd
}"
@click="$bus.$emit('execCommand', 'BACK')"
>
<span class="icon iconfont iconhoutui-shi"></span>
<span class="text">{{ $t('toolbar.undo') }}</span>
</div>
<div
v-if="item === 'forward'"
class="toolbarBtn"
:class="{
disabled: readonly || forwardEnd
}"
@click="$bus.$emit('execCommand', 'FORWARD')"
>
<span class="icon iconfont iconqianjin1"></span>
<span class="text">{{ $t('toolbar.redo') }}</span>
</div>
<div
v-if="item === 'painter'"
class="toolbarBtn"
:class="{
disabled: activeNodes.length <= 0 || hasGeneralization,
active: isInPainter
}"
@click="$bus.$emit('startPainter')"
>
<span class="icon iconfont iconjiedian"></span>
<span class="text">{{ $t('toolbar.painter') }}</span>
</div>
<div
v-if="item === 'siblingNode'"
class="toolbarBtn"
:class="{
disabled: activeNodes.length <= 0 || hasRoot || hasGeneralization
}"
@click="$bus.$emit('execCommand', 'INSERT_NODE')"
>
<span class="icon iconfont iconjiedian"></span>
<span class="text">{{ $t('toolbar.insertSiblingNode') }}</span>
</div>
<div
v-if="item === 'childNode'"
class="toolbarBtn"
:class="{
disabled: activeNodes.length <= 0 || hasGeneralization
}"
@click="$bus.$emit('execCommand', 'INSERT_CHILD_NODE')"
>
<span class="icon iconfont icontianjiazijiedian"></span>
<span class="text">{{ $t('toolbar.insertChildNode') }}</span>
</div>
<div
v-if="item === 'deleteNode'"
class="toolbarBtn"
:class="{
disabled: activeNodes.length <= 0
}"
@click="$bus.$emit('execCommand', 'REMOVE_NODE')"
>
<span class="icon iconfont iconshanchu"></span>
<span class="text">{{ $t('toolbar.deleteNode') }}</span>
</div>
<div
v-if="item === 'image'"
class="toolbarBtn"
:class="{
disabled: activeNodes.length <= 0
}"
@click="$bus.$emit('showNodeImage')"
>
<span class="icon iconfont iconimage"></span>
<span class="text">{{ $t('toolbar.image') }}</span>
</div>
<div
v-if="item === 'icon'"
class="toolbarBtn"
:class="{
disabled: activeNodes.length <= 0
}"
@click="showNodeIcon"
>
<span class="icon iconfont iconxiaolian"></span>
<span class="text">{{ $t('toolbar.icon') }}</span>
</div>
<div
v-if="item === 'link'"
class="toolbarBtn"
:class="{
disabled: activeNodes.length <= 0
}"
@click="$bus.$emit('showNodeLink')"
>
<span class="icon iconfont iconchaolianjie"></span>
<span class="text">{{ $t('toolbar.link') }}</span>
</div>
<div
v-if="item === 'note'"
class="toolbarBtn"
:class="{
disabled: activeNodes.length <= 0
}"
@click="$bus.$emit('showNodeNote')"
>
<span class="icon iconfont iconflow-Mark"></span>
<span class="text">{{ $t('toolbar.note') }}</span>
</div>
<div
v-if="item === 'tag'"
class="toolbarBtn"
:class="{
disabled: activeNodes.length <= 0
}"
@click="$bus.$emit('showNodeTag')"
>
<span class="icon iconfont iconbiaoqian"></span>
<span class="text">{{ $t('toolbar.tag') }}</span>
</div>
<div
v-if="item === 'summary'"
class="toolbarBtn"
:class="{
disabled: activeNodes.length <= 0 || hasRoot || hasGeneralization
}"
@click="$bus.$emit('execCommand', 'ADD_GENERALIZATION')"
>
<span class="icon iconfont icongaikuozonglan"></span>
<span class="text">{{ $t('toolbar.summary') }}</span>
</div>
<div
v-if="item === 'associativeLine'"
class="toolbarBtn"
:class="{
disabled: activeNodes.length <= 0 || hasGeneralization
}"
@click="$bus.$emit('createAssociativeLine')"
>
<span class="icon iconfont iconlianjiexian"></span>
<span class="text">{{ $t('toolbar.associativeLine') }}</span>
</div>
<div
v-if="item === 'formula'"
class="toolbarBtn"
:class="{
disabled: activeNodes.length <= 0 || hasGeneralization
}"
@click="showFormula"
>
<span class="icon iconfont icongongshi"></span>
<span class="text">{{ $t('toolbar.formula') }}</span>
</div>
</template>
</div>
</template>
<script>
import { mapState, mapMutations } from 'vuex'
export default {
props: {
dir: {
type: String,
default: 'h' // hv
},
list: {
type: Array,
default() {
return []
}
}
},
data() {
return {
activeNodes: [],
backEnd: false,
forwardEnd: true,
readonly: false,
isFullDataFile: false,
timer: null,
isInPainter: false
}
},
computed: {
...mapState(['isDark']),
hasRoot() {
return (
this.activeNodes.findIndex(node => {
return node.isRoot
}) !== -1
)
},
hasGeneralization() {
return (
this.activeNodes.findIndex(node => {
return node.isGeneralization
}) !== -1
)
}
},
created() {
this.$bus.$on('mode_change', this.onModeChange)
this.$bus.$on('node_active', this.onNodeActive)
this.$bus.$on('back_forward', this.onBackForward)
this.$bus.$on('painter_start', this.onPainterStart)
this.$bus.$on('painter_end', this.onPainterEnd)
},
beforeDestroy() {
this.$bus.$off('mode_change', this.onModeChange)
this.$bus.$off('node_active', this.onNodeActive)
this.$bus.$off('back_forward', this.onBackForward)
this.$bus.$off('painter_start', this.onPainterStart)
this.$bus.$off('painter_end', this.onPainterEnd)
},
methods: {
...mapMutations(['setActiveSidebar']),
//
onModeChange(mode) {
this.readonly = mode === 'readonly'
},
//
onNodeActive(...args) {
this.activeNodes = [...args[1]]
},
// 退
onBackForward(index, len) {
this.backEnd = index <= 0
this.forwardEnd = index >= len - 1
},
//
onPainterStart() {
this.isInPainter = true
},
//
onPainterEnd() {
this.isInPainter = false
},
//
showNodeIcon() {
this.$bus.$emit('close_node_icon_toolbar')
this.setActiveSidebar('nodeIconSidebar')
},
//
showFormula() {
this.setActiveSidebar('formulaSidebar')
}
}
}
</script>
<style lang="less" scoped>
.toolbarNodeBtnList {
display: flex;
&.isDark {
.toolbarBtn {
color: hsla(0, 0%, 100%, 0.9);
.icon {
background: transparent;
border-color: transparent;
}
&:hover {
&:not(.disabled) {
.icon {
background: hsla(0, 0%, 100%, 0.05);
}
}
}
&.disabled {
color: #54595f;
}
}
}
.toolbarBtn {
display: flex;
justify-content: center;
flex-direction: column;
cursor: pointer;
margin-right: 20px;
&:last-of-type {
margin-right: 0;
}
&:hover {
&:not(.disabled) {
.icon {
background: #f5f5f5;
}
}
}
&.active {
.icon {
background: #f5f5f5;
}
}
&.disabled {
color: #bcbcbc;
cursor: not-allowed;
pointer-events: none;
}
.icon {
display: flex;
height: 26px;
background: #fff;
border-radius: 4px;
border: 1px solid #e9e9e9;
justify-content: center;
flex-direction: column;
text-align: center;
padding: 0 5px;
}
.text {
margin-top: 3px;
}
}
&.v {
display: block;
width: 120px;
flex-wrap: wrap;
.toolbarBtn {
flex-direction: row;
justify-content: flex-start;
margin-bottom: 10px;
width: 100%;
margin-right: 0;
&:last-of-type {
margin-bottom: 0;
}
.icon {
margin-right: 10px;
}
.text {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
}
}
</style>