605 lines
19 KiB
Vue
605 lines
19 KiB
Vue
<template>
|
||
<view class='index-list'>
|
||
<view class='index-list__head'>
|
||
<input v-model="citySearch" :placeholder='placeholder' class="index-list__input"
|
||
placeholder-class="index-list__input__placeholder" />
|
||
</view>
|
||
<div>
|
||
<div class='index-list__scroller'>
|
||
<div ref="bigDataTablePanel" class="index-list__big-data__table-panel">
|
||
<div ref="bigDataTableBody" class="index-list__big-data__table-body">
|
||
<div ref="bigDataTableDataPanel" id="bigDataTableDataPanel"
|
||
class="index-list__big-data__table-data-panel" @touchstart="bigDataTouchStartEvent"
|
||
@touchmove.stop.prevent="bigDataScrollEvent" @touchend="bigDataTouchEndEvent"
|
||
@mousewheel="bigDataScrollEvent">
|
||
<div ref="bigDataTableDataMarginSpace" :style="{'margin-top':newMarginTop+'px'}"></div>
|
||
<div v-for='item in bigDataFilteredFlatWithLineInfoCurrent' :key='item.id'>
|
||
<div v-if='item.__line_info__.isEmptySpace'
|
||
class="index-list__group-cell index-list__group-cell--empty-space"></div>
|
||
<div v-else-if='!item.__line_info__.isEmptySpace&&item.__line_info__.isHead'
|
||
class="index-list__group-head">{{item.username}}</div>
|
||
<div v-else-if='!item.__line_info__.isEmptySpace&&!item.__line_info__.isHead'
|
||
class="index-list__group-cell" @click="()=>{ itemClickHandler(item)}" :key="item.id"
|
||
style="display: flex;" @longpress="()=>{itemLongPress(item)}">
|
||
<view>
|
||
<image src="../../static/images/tx.png"
|
||
style="width:50rpx;height: 50rpx;margin-top: 10rpx;"></image>
|
||
</view>
|
||
<span
|
||
style="padding-left: 20rpx;font-size:34rpx ;letter-spacing: 1rpx;">{{item.username}}</span>
|
||
<span
|
||
style="padding-left: 20rpx;font-size:34rpx ;letter-spacing: 1rpx;">({{item.phone}})</span>
|
||
</div>
|
||
|
||
</div>
|
||
<div v-for='groupKey in Object.keys(bigDataFiltered)' style='' :key='groupKey'>
|
||
<div class="index-list__group-head"
|
||
:id='"list-archor-"+ encodeURIComponent(groupKey).replace("%","_")'>
|
||
{{groupKey}}
|
||
</div>
|
||
<div class="index-list__group-cell" v-for='city in dataFiltered[groupKey]'
|
||
@click="()=>{itemClickHandler(city)}" :clickable='true' :key="city.id">
|
||
{{city.username}}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<view v-if='useIndex&&dataFiltered&&Object.keys(dataFiltered).length>0' class='index-list__index'
|
||
@touchmove="indexTouchMoveHandler" @touchstart="indexTouchMoveHandler" @touchend="isZoomActiveIndex=false">
|
||
<div class='index-list__index__wrapper'>
|
||
<div v-for='groupKey in Object.keys(dataFiltered)' :key='groupKey' class='index-list__index__letter'
|
||
:class='{"index-list__index__letter--active":currentActiveIndex===groupKey&&isZoomActiveIndex,
|
||
"index-list__index__letter--active2":currentActiveIndex===groupKey}'>
|
||
{{groupKey}}
|
||
</div>
|
||
</div>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import {
|
||
pinyin
|
||
} from "@/api/convertPinyin.js";
|
||
export default {
|
||
name: "missthee-indexlist",
|
||
props: {
|
||
data: {
|
||
type: Object,
|
||
default: function() {
|
||
return {}
|
||
}
|
||
},
|
||
placeholder: {
|
||
type: String,
|
||
default: function() {
|
||
return '输入关键字查询'
|
||
}
|
||
},
|
||
useIndex: {
|
||
type: Boolean,
|
||
default: function() {
|
||
return true
|
||
}
|
||
},
|
||
},
|
||
data() {
|
||
return {
|
||
dataFiltered: {},
|
||
currentActiveIndex: '',
|
||
isZoomActiveIndex: false,
|
||
citySearch: '',
|
||
citySeatchDebounce: null,
|
||
bigDataFilteredLineHeightTotal: 0,
|
||
bigDataFiltered: {},
|
||
bigDataFilteredFlatWithLineInfo: [],
|
||
bigDataFilteredFlatWithLineInfoCurrent: [],
|
||
bigDataTableDataPanelEl: null,
|
||
bigDataParam: {
|
||
scrollHeight: 0,
|
||
dataHeadHeight: 35, // 索引行高
|
||
dataRowHeight: 45, // 数据行高
|
||
},
|
||
bigDataComputedParam: {
|
||
dataRowTopMax: 0, //数据行滑到底,移动的最大距离
|
||
dataRowTop: 0, //数据行当前移动的距离
|
||
},
|
||
|
||
bigDataScrollActionParam: {
|
||
speed: 0,
|
||
speedMax: 50,
|
||
resistance: 0.5,
|
||
prePositionY: null,
|
||
preTimestamp: null,
|
||
isMouseDown: false,
|
||
timeoutObj: null
|
||
},
|
||
newMarginTop: 0,
|
||
islongPress: false, //长按记录变量
|
||
}
|
||
},
|
||
watch: {
|
||
data: {
|
||
immediate: true,
|
||
handler() {
|
||
this.buildDataFiltered()
|
||
}
|
||
},
|
||
citySearch() {
|
||
if (this.citySeatchDebounce) {
|
||
clearTimeout(this.citySeatchDebounce)
|
||
this.citySeatchDebounce = null
|
||
}
|
||
this.citySeatchDebounce = setTimeout(() => {
|
||
this.buildDataFiltered()
|
||
}, 200)
|
||
},
|
||
dataFiltered: {
|
||
deep: true,
|
||
handler() {
|
||
this.bigDataComputedParam.dataRowTop = 0
|
||
this.bigDataBuildData()
|
||
this.bigDataUpdateRows()
|
||
}
|
||
}
|
||
},
|
||
mounted() {
|
||
this.bigDataTableDataPanelEl = this.$refs.bigDataTableDataPanel
|
||
// #ifdef H5
|
||
this.bigDataParam.scrollHeight = this.bigDataTableDataPanelEl.offsetHeight
|
||
// #endif
|
||
// #ifdef APP-VUE || APP
|
||
let view = uni.createSelectorQuery().in(this).select("#bigDataTableDataPanel")
|
||
view.fields({
|
||
size: true
|
||
}, res => {
|
||
this.bigDataParam.scrollHeight = res.height - 100
|
||
this.afterHeight = true;
|
||
}).exec()
|
||
// #endif
|
||
this.bigDataAddEvent()
|
||
this.bigDataBuildData()
|
||
this.bigDataUpdateRows()
|
||
this.bigDataScrollAminate()
|
||
},
|
||
beforeDestroy() {
|
||
this.bigDataClearScrollAnimate()
|
||
this.bigDataRemoveEvent()
|
||
},
|
||
methods: {
|
||
indexTouchMoveHandler(e) {
|
||
this.isZoomActiveIndex = true
|
||
const touch = e.touches[0];
|
||
const target = e.currentTarget || e.target
|
||
let currentIndex = Math.floor((touch.clientY + Object.keys(this.dataFiltered).length * 15 / 2 -
|
||
target.offsetTop) / 15)
|
||
currentIndex = Math.min(Object.keys(this.dataFiltered).length - 1, currentIndex)
|
||
currentIndex = Math.max(0, currentIndex)
|
||
if (Object.keys(this.dataFiltered)[currentIndex] !== this.currentActiveIndex) {
|
||
this.currentActiveIndex = Object.keys(this.dataFiltered)[currentIndex]
|
||
let currentStartLine = this.bigDataFilteredFlatWithLineInfo.find(item => item.id === 'Head:' + this
|
||
.currentActiveIndex)
|
||
this.bigDataComputedParam.dataRowTop = currentStartLine.__line_info__.totalHeight -
|
||
currentStartLine
|
||
.__line_info__.currentHeight
|
||
this.bigDataUpdateRows()
|
||
}
|
||
if ("undefined" !== typeof event) {
|
||
event.preventDefault()
|
||
event.stopPropagation()
|
||
}
|
||
},
|
||
itemClickHandler(item) {
|
||
if (this.islongPress) {
|
||
return
|
||
}
|
||
let result = {
|
||
...item
|
||
}
|
||
for (let key of Object.keys(result)) {
|
||
if (key === '__line_info__') {
|
||
delete result[key]
|
||
}
|
||
}
|
||
|
||
this.$emit('select-item', result)
|
||
},
|
||
itemLongPress(item) {
|
||
this.islongPress = true
|
||
let result = {
|
||
...item
|
||
}
|
||
for (let key of Object.keys(result)) {
|
||
if (key === '__line_info__') {
|
||
delete result[key]
|
||
}
|
||
}
|
||
|
||
let _this = this
|
||
uni.setClipboardData({
|
||
data: result.phone,
|
||
success: function() {
|
||
uni.showToast({
|
||
title: '复制成功',
|
||
icon: 'success'
|
||
});
|
||
setTimeout(() => {
|
||
_this.islongPress = false
|
||
}, 2000)
|
||
}
|
||
});
|
||
},
|
||
buildDataFiltered() {
|
||
if (!this.data) {
|
||
return {}
|
||
}
|
||
const resultObj = {}
|
||
for (const groupkey of Object.keys(this.data)) {
|
||
const cityListResult = this.data[groupkey].filter(item =>
|
||
item.username.toLowerCase().indexOf(this
|
||
.citySearch.toLowerCase()) >= 0
|
||
)
|
||
if (cityListResult && cityListResult.length > 0) {
|
||
resultObj[groupkey] = cityListResult
|
||
}
|
||
}
|
||
this.dataFiltered = resultObj
|
||
},
|
||
bigDataAddEvent() {
|
||
// #ifdef APP-VUE || APP
|
||
// plus.globalEvent.addEventListener('mousewheel', this.bigDataScrollEvent);
|
||
// plus.globalEvent.addEventListener('touchmove', this.bigDataScrollEvent);
|
||
// plus.globalEvent.addEventListener('touchstart', this.bigDataTouchStartEvent);
|
||
// plus.globalEvent.addEventListener('touchend', this.bigDataTouchEndEvent);
|
||
// #endif
|
||
// #ifdef H5
|
||
this.bigDataTableDataPanelEl.addEventListener('mousewheel', this.bigDataScrollEvent);
|
||
this.bigDataTableDataPanelEl.addEventListener('touchmove', this.bigDataScrollEvent);
|
||
this.bigDataTableDataPanelEl.addEventListener('touchstart', this.bigDataTouchStartEvent);
|
||
this.bigDataTableDataPanelEl.addEventListener('touchend', this.bigDataTouchEndEvent);
|
||
// #endif
|
||
|
||
},
|
||
bigDataRemoveEvent() {
|
||
this.bigDataTableDataPanelEl.removeEventListener('mousewheel', this.bigDataScrollEvent);
|
||
this.bigDataTableDataPanelEl.removeEventListener('touchmove', this.bigDataScrollEvent);
|
||
this.bigDataTableDataPanelEl.removeEventListener('touchstart', this.bigDataTouchStartEvent);
|
||
this.bigDataTableDataPanelEl.removeEventListener('touchend', this.bigDataTouchEndEvent);
|
||
},
|
||
bigDataTouchStartEvent(e) {
|
||
this.bigDataScrollActionParam.isMouseDown = true
|
||
this.bigDataScrollActionParam.speed = 0
|
||
},
|
||
bigDataTouchEndEvent(e) {
|
||
this.bigDataScrollActionParam.isMouseDown = false
|
||
this.bigDataScrollActionParam.prePositionY = null
|
||
},
|
||
bigDataScrollEvent(e) {
|
||
let scrollEvent = e;
|
||
// if (scrollEvent instanceof WheelEvent) {
|
||
// #ifdef H5
|
||
this.bigDataComputedParam.dataRowTop += (scrollEvent.wheelDelta < 0 ? 1 : -1) * 30;
|
||
if (this.bigDataComputedParam.dataRowTop <= 0) {
|
||
this.bigDataComputedParam.dataRowTop = 0; //滑块最多滑到顶部
|
||
} else if (this.bigDataComputedParam.dataRowTop >= this.bigDataComputedParam.dataRowTopMax) {
|
||
this.bigDataComputedParam.dataRowTop = this.bigDataComputedParam.dataRowTopMax; //滑块最多滑到最底部
|
||
} else {
|
||
e.preventDefault(); //禁用滑轮滚动默认事件。当表格滑动到边缘时再启用默认滚动事件
|
||
}
|
||
// #endif
|
||
// } else
|
||
// if (scrollEvent instanceof TouchEvent) {
|
||
// #ifdef APP||APP-VUE
|
||
if (this.bigDataScrollActionParam.isMouseDown) {
|
||
let positionY = scrollEvent.changedTouches[0].clientY
|
||
let timeStamp = scrollEvent.timeStamp
|
||
let step = 0
|
||
this.bigDataScrollActionParam.prePositionY = this.bigDataScrollActionParam.prePositionY ||
|
||
positionY
|
||
this.bigDataScrollActionParam.preTimeStamp = this.bigDataScrollActionParam.preTimeStamp ||
|
||
timeStamp
|
||
let timeDuration = timeStamp - this.bigDataScrollActionParam.preTimeStamp;
|
||
let velocity;
|
||
if (timeDuration === 0) {
|
||
velocity = 0
|
||
} else {
|
||
velocity = (positionY - this.bigDataScrollActionParam.prePositionY) / timeDuration
|
||
}
|
||
if (this.bigDataScrollActionParam.prePositionY !== null) {
|
||
step = positionY - this.bigDataScrollActionParam.prePositionY
|
||
this.bigDataComputedParam.dataRowTop -= step
|
||
}
|
||
this.bigDataScrollActionParam.prePositionY = positionY
|
||
this.bigDataScrollActionParam.preTimeStamp = timeStamp
|
||
this.bigDataScrollActionParam.speed = velocity * 16
|
||
e.preventDefault()
|
||
e.stopPropagation()
|
||
}
|
||
// #endif
|
||
// }
|
||
this.bigDataUpdateRows();
|
||
},
|
||
bigDataBuildData() {
|
||
this.bigDataFilteredFlatWithLineInfo = []
|
||
this.bigDataFilteredLineHeightTotal = 0
|
||
for (let key of Object.keys(this.dataFiltered)) {
|
||
if (this.dataFiltered[key] && this.dataFiltered[key].length > 0) {
|
||
this.bigDataFilteredLineHeightTotal += this.bigDataParam.dataHeadHeight
|
||
this.bigDataFilteredFlatWithLineInfo.push({
|
||
id: "Head:" + key,
|
||
username: key,
|
||
__line_info__: {
|
||
isEmptySpace: false,
|
||
isHead: true,
|
||
currentHeight: this.bigDataParam.dataHeadHeight,
|
||
totalHeight: this.bigDataFilteredLineHeightTotal
|
||
}
|
||
})
|
||
this.dataFiltered[key].forEach((item) => {
|
||
this.bigDataFilteredLineHeightTotal += this.bigDataParam.dataRowHeight
|
||
this.bigDataFilteredFlatWithLineInfo.push({
|
||
id: "Row:" + item.id,
|
||
username: item.username,
|
||
phone: item.phone,
|
||
__line_info__: {
|
||
isEmptySpace: false,
|
||
isHead: false,
|
||
currentHeight: this.bigDataParam.dataRowHeight,
|
||
totalHeight: this.bigDataFilteredLineHeightTotal
|
||
}
|
||
})
|
||
})
|
||
}
|
||
}
|
||
this.bigDataFilteredLineHeightTotal += this.bigDataParam.dataRowHeight
|
||
this.bigDataFilteredFlatWithLineInfo.push({
|
||
id: "EmptyFooter",
|
||
username: '',
|
||
__line_info__: {
|
||
isEmptySpace: true,
|
||
isHead: false,
|
||
currentHeight: this.bigDataParam.dataRowHeight,
|
||
totalHeight: this.bigDataFilteredLineHeightTotal
|
||
}
|
||
})
|
||
//计算出数据区域滑动到最后一条数据,所需要的位移距离
|
||
this.bigDataComputedParam.dataRowTopMax = Math.max(this.bigDataFilteredLineHeightTotal - this.bigDataParam
|
||
.scrollHeight, 0)
|
||
},
|
||
bigDataUpdateRows() {
|
||
this.bigDataComputedParam.dataRowTop = Math.max(0, this.bigDataComputedParam.dataRowTop)
|
||
this.bigDataComputedParam.dataRowTop = Math.min(this.bigDataComputedParam.dataRowTop, this
|
||
.bigDataComputedParam.dataRowTopMax)
|
||
if (this.bigDataFilteredFlatWithLineInfo.length > 0) {
|
||
//更新数据区的数据,根据滚动的距离,确定可见的第一条数据下标(此方法保证可见数据行内容的更新。注释掉此方法,拖动滚动条,数据会在开始部分一直循环)
|
||
//遍历数据,插入窗口中可见的数据行
|
||
let startIndex = null
|
||
let endIndex = null
|
||
|
||
for (let i = parseInt(this.bigDataComputedParam.dataRowTop / Math.max(this.bigDataParam.dataRowHeight,
|
||
this.bigDataParam.dataHeadHeight), 10) - 1; i < this.bigDataFilteredFlatWithLineInfo
|
||
.length; i++) {
|
||
if (i < 0) {
|
||
continue
|
||
}
|
||
const totalHeight = this.bigDataFilteredFlatWithLineInfo[i].__line_info__.totalHeight
|
||
if (totalHeight >= this.bigDataComputedParam.dataRowTop && startIndex === null) {
|
||
startIndex = i
|
||
}
|
||
if (totalHeight >= (this.bigDataComputedParam.dataRowTop + this.bigDataParam.scrollHeight) &&
|
||
endIndex === null) {
|
||
endIndex = Math.min(i + 3, this.bigDataFilteredFlatWithLineInfo.length)
|
||
} else if (endIndex === null && this.bigDataFilteredFlatWithLineInfo.length < 10) {
|
||
endIndex = this.bigDataFilteredFlatWithLineInfo.length
|
||
}
|
||
if (startIndex !== null && endIndex !== null) {
|
||
break
|
||
}
|
||
}
|
||
startIndex = startIndex || 0
|
||
endIndex = endIndex || 0
|
||
this.bigDataFilteredFlatWithLineInfoCurrent = this.bigDataFilteredFlatWithLineInfo.slice(startIndex,
|
||
endIndex)
|
||
if (this.bigDataFilteredFlatWithLineInfoCurrent && this.bigDataFilteredFlatWithLineInfoCurrent[0]) {
|
||
const tmp = this.bigDataFilteredFlatWithLineInfoCurrent[0]
|
||
let firstRowHeight = tmp.__line_info__.currentHeight || 0
|
||
let firstRowTotalHeight = tmp.__line_info__.totalHeight || 0
|
||
//数据区实现拖动滑条的位移效果(保证数据行的滚动效果,注释此方法,拖动滚动条,数据无滚动效果,但内容会更新)
|
||
this.newMarginTop = firstRowTotalHeight - this.bigDataComputedParam.dataRowTop - firstRowHeight
|
||
if (!this.isZoomActiveIndex) {
|
||
this.currentActiveIndex = pinyin.getFullChars(tmp.username).charAt(0).toUpperCase();
|
||
}
|
||
}
|
||
|
||
}
|
||
},
|
||
bigDataScrollAminate() {
|
||
this.bigDataScrollActionParam.timeoutObj = setInterval(() => {
|
||
if (Math.abs(this.bigDataScrollActionParam.speed) > 0 && !this.bigDataScrollActionParam
|
||
.isMouseDown) {
|
||
this.bigDataScrollActionParam.speed = (this.bigDataScrollActionParam.speed >= 0 ? 1 : -1) *
|
||
Math.min(this.bigDataScrollActionParam.speedMax, Math.max(0, Math.abs(this
|
||
.bigDataScrollActionParam.speed) - this.bigDataScrollActionParam
|
||
.resistance))
|
||
this.bigDataComputedParam.dataRowTop -= this.bigDataScrollActionParam.speed
|
||
this.bigDataUpdateRows()
|
||
}
|
||
}, 16)
|
||
},
|
||
bigDataClearScrollAnimate() {
|
||
if (this.bigDataScrollActionParam.timeoutObj) {
|
||
clearInterval(this.bigDataScrollActionParam.timeoutObj)
|
||
this.bigDataScrollActionParam.timeoutObj = null
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang='scss' scoped>
|
||
* {
|
||
font-family: Consolas, sans-serif;
|
||
box-sizing: border-box !important;
|
||
margin: 0;
|
||
padding: 0;
|
||
}
|
||
|
||
|
||
.index-list__index__letter--active2 {
|
||
color: red;
|
||
}
|
||
|
||
.index-list__index__letter {
|
||
margin: 5px 0;
|
||
font-size: 20px;
|
||
}
|
||
|
||
.index-list {
|
||
position: absolute;
|
||
top: 0;
|
||
bottom: 0;
|
||
width: 100%;
|
||
|
||
&__head {
|
||
position: absolute;
|
||
top: 0;
|
||
width: 100%;
|
||
height: 50px;
|
||
overflow: hidden;
|
||
background-color: $uni-bg-color;
|
||
border-bottom: 1px solid $uni-bg-color-grey;
|
||
}
|
||
|
||
&__input {
|
||
box-sizing: border-box;
|
||
width: 90%;
|
||
height: 30px;
|
||
padding: 0 20px;
|
||
margin: auto;
|
||
height: 30px;
|
||
margin: 10px auto;
|
||
line-height: 30px;
|
||
background-color: $uni-bg-color-grey;
|
||
border-radius: 30px;
|
||
font-size: 12px;
|
||
color: $uni-text-color;
|
||
|
||
&__placeholder {
|
||
text-align: center;
|
||
color: $uni-text-color-placeholder;
|
||
}
|
||
}
|
||
|
||
&__scroller {
|
||
position: absolute;
|
||
top: 50px;
|
||
bottom: 0;
|
||
width: 100%;
|
||
background-color: white;
|
||
overflow-x: hidden;
|
||
overflow-y: auto;
|
||
}
|
||
|
||
&__big-data {
|
||
|
||
&__table-panel {
|
||
height: 100%;
|
||
width: 100%;
|
||
}
|
||
|
||
&__table-body {
|
||
/*因为数据区与滚动条要使用position:absolute做成左右固定布局,table-body作为其两节点的父节点,使用position: relative*/
|
||
position: relative;
|
||
height: 100%;
|
||
overflow: hidden;
|
||
background-color: white;
|
||
}
|
||
|
||
&__table-data-panel {
|
||
overflow: hidden;
|
||
position: absolute;
|
||
left: 0;
|
||
/*right值宽度等于滚动条的宽度。也可不设置,但滚动条会覆盖表格的最右侧*/
|
||
/*right: 15px;*/
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
}
|
||
|
||
&__group-head {
|
||
box-sizing: border-box;
|
||
background-color: $uni-bg-color-grey;
|
||
color: $uni-text-color-grey;
|
||
height: 35px;
|
||
line-height: 45px;
|
||
padding: 0 0 0 15px;
|
||
}
|
||
|
||
&__group-cell {
|
||
box-sizing: border-box;
|
||
background-color: $uni-bg-color;
|
||
color: $uni-text-color;
|
||
font-size: 14px;
|
||
font-family: SourceHanSansSC-Regular, SourceHanSansSC;
|
||
height: 45px;
|
||
line-height: 45px;
|
||
padding: 0 0 0 15px;
|
||
|
||
&:after {
|
||
display: block;
|
||
position: absolute;
|
||
content: '';
|
||
width: 100%;
|
||
height: 1px;
|
||
background-color: $uni-bg-color-grey;
|
||
}
|
||
|
||
&:active {
|
||
background-color: $uni-bg-color-hover;
|
||
}
|
||
|
||
&--empty-space {
|
||
&:active {
|
||
background-color: white;
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
&__index {
|
||
position: absolute;
|
||
right: 0;
|
||
top: 50%;
|
||
transform: translateY(-50%);
|
||
|
||
&__wrapper {
|
||
width: 20px;
|
||
margin: 0 7px 0 0;
|
||
text-align: center;
|
||
background-color: rgba(0, 0, 0, 0.03);
|
||
border-radius: 10px;
|
||
color: $uni-text-color-grey;
|
||
padding: 10px 0;
|
||
font-family: Consolas, sans-serif;
|
||
}
|
||
|
||
&__letter {
|
||
display: block;
|
||
height: 15px !important;
|
||
line-height: 15px !important;
|
||
transition: transform 0.1s;
|
||
|
||
&--active {
|
||
transition: none;
|
||
font-weight: bold;
|
||
font-size: 50px;
|
||
transform: translateX(-70px);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</style> |