添加音效用户预设
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
<template>
|
||||
<base-btn min :class="[$style.newPreset, {[$style.editing]: isEditing}]" :aria-label="$t('player__sound_effect_biquad_filter_save_btn')" @click="handleEditing($event)">
|
||||
<svg-icon name="plus" />
|
||||
<base-input ref="input" :class="$style.newPresetInput" :value="newPresetName" :placeholder="$t('player__sound_effect_biquad_filter_save_input')" @keyup.enter="handleSave($event)" @blur="handleSave($event)" />
|
||||
</base-btn>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, nextTick } from '@common/utils/vueTools'
|
||||
import { appSetting } from '@renderer/store/setting'
|
||||
import { saveUserConvolutionPreset } from '@renderer/store/soundEffect'
|
||||
|
||||
const isEditing = ref(false)
|
||||
const input = ref(false)
|
||||
const newPresetName = ref('')
|
||||
|
||||
const handleEditing = () => {
|
||||
if (isEditing.value) return
|
||||
// if (!this.newPresetName) this.newPresetName = this.listName
|
||||
isEditing.value = true
|
||||
nextTick(() => {
|
||||
input.value.$el.focus()
|
||||
})
|
||||
}
|
||||
|
||||
const handleSave = (event) => {
|
||||
let name = event.target.value.trim()
|
||||
newPresetName.value = event.target.value = ''
|
||||
isEditing.value = false
|
||||
if (!name) return
|
||||
if (name.length > 20) name = name.substring(0, 20)
|
||||
saveUserConvolutionPreset({
|
||||
id: Date.now().toString(),
|
||||
name,
|
||||
source: appSetting['player.soundEffect.convolution.fileName'],
|
||||
mainGain: appSetting['player.soundEffect.convolution.mainGain'],
|
||||
sendGain: appSetting['player.soundEffect.convolution.sendGain'],
|
||||
})
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="less" module>
|
||||
@import '@renderer/assets/styles/layout.less';
|
||||
|
||||
.newPreset {
|
||||
position: relative;
|
||||
border: 1px dashed var(--color-primary-font-hover);
|
||||
// background-color: var(--color-main-background);
|
||||
color: var(--color-primary-font-hover);
|
||||
opacity: .7;
|
||||
height: 22px;
|
||||
|
||||
&.editing {
|
||||
opacity: 1;
|
||||
width: 90px;
|
||||
|
||||
svg {
|
||||
display: none;
|
||||
}
|
||||
.newPresetInput {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
:global {
|
||||
.svg-icon {
|
||||
vertical-align: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
.newPresetInput {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
// line-height: 16px;
|
||||
background: none !important;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
font-family: inherit;
|
||||
box-sizing: border-box;
|
||||
padding: 0 3px;
|
||||
border-radius: 0;
|
||||
display: none;
|
||||
&::placeholder {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,99 @@
|
||||
<template>
|
||||
<base-btn min :class="[$style.newPreset, {[$style.editing]: isEditing}]" :aria-label="$t('player__sound_effect_biquad_filter_save_btn')" @click="handleEditing($event)">
|
||||
<svg-icon name="plus" />
|
||||
<base-input ref="input" :class="$style.newPresetInput" :value="newPresetName" :placeholder="$t('player__sound_effect_biquad_filter_save_input')" @keyup.enter="handleSave($event)" @blur="handleSave($event)" />
|
||||
</base-btn>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, nextTick } from '@common/utils/vueTools'
|
||||
import { appSetting } from '@renderer/store/setting'
|
||||
import { saveUserEQPreset } from '@renderer/store/soundEffect'
|
||||
|
||||
const isEditing = ref(false)
|
||||
const input = ref(false)
|
||||
const newPresetName = ref('')
|
||||
|
||||
const handleEditing = () => {
|
||||
if (isEditing.value) return
|
||||
// if (!this.newPresetName) this.newPresetName = this.listName
|
||||
isEditing.value = true
|
||||
nextTick(() => {
|
||||
input.value.$el.focus()
|
||||
})
|
||||
}
|
||||
|
||||
const handleSave = (event) => {
|
||||
let name = event.target.value.trim()
|
||||
newPresetName.value = event.target.value = ''
|
||||
isEditing.value = false
|
||||
if (!name) return
|
||||
if (name.length > 20) name = name.substring(0, 20)
|
||||
saveUserEQPreset({
|
||||
id: Date.now().toString(),
|
||||
name,
|
||||
hz31: appSetting['player.soundEffect.biquadFilter.hz31'],
|
||||
hz62: appSetting['player.soundEffect.biquadFilter.hz62'],
|
||||
hz125: appSetting['player.soundEffect.biquadFilter.hz125'],
|
||||
hz250: appSetting['player.soundEffect.biquadFilter.hz250'],
|
||||
hz500: appSetting['player.soundEffect.biquadFilter.hz500'],
|
||||
hz1000: appSetting['player.soundEffect.biquadFilter.hz1000'],
|
||||
hz2000: appSetting['player.soundEffect.biquadFilter.hz2000'],
|
||||
hz4000: appSetting['player.soundEffect.biquadFilter.hz4000'],
|
||||
hz8000: appSetting['player.soundEffect.biquadFilter.hz8000'],
|
||||
hz16000: appSetting['player.soundEffect.biquadFilter.hz16000'],
|
||||
})
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="less" module>
|
||||
@import '@renderer/assets/styles/layout.less';
|
||||
|
||||
.newPreset {
|
||||
position: relative;
|
||||
border: 1px dashed var(--color-primary-font-hover);
|
||||
// background-color: var(--color-main-background);
|
||||
color: var(--color-primary-font-hover);
|
||||
opacity: .7;
|
||||
height: 22px;
|
||||
|
||||
&.editing {
|
||||
opacity: 1;
|
||||
width: 90px;
|
||||
|
||||
svg {
|
||||
display: none;
|
||||
}
|
||||
.newPresetInput {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
:global {
|
||||
.svg-icon {
|
||||
vertical-align: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
.newPresetInput {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
// line-height: 16px;
|
||||
background: none !important;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
font-family: inherit;
|
||||
box-sizing: border-box;
|
||||
padding: 0 3px;
|
||||
border-radius: 0;
|
||||
display: none;
|
||||
&::placeholder {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -27,13 +27,19 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div :class="['scroll', $style.saveList]">
|
||||
<base-btn v-for="item in userPresetList" :key="item.id" min @click="handleSetPreset(item)" @contextmenu="handleRemovePreset(item.id)">{{ item.name }}</base-btn>
|
||||
<AddConvolutionPresetBtn />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
// import { ref } from '@common/utils/vueTools'
|
||||
import { ref, onMounted } from '@common/utils/vueTools'
|
||||
import { appSetting, updateSetting } from '@renderer/store/setting'
|
||||
import { convolutions } from '@renderer/plugins/player'
|
||||
import AddConvolutionPresetBtn from './AddConvolutionPresetBtn'
|
||||
import { getUserConvolutionPresetList, removeUserConvolutionPreset } from '@renderer/store/soundEffect'
|
||||
|
||||
const updateConvolution = val => {
|
||||
const target = convolutions.find(c => c.source == val)
|
||||
@@ -54,6 +60,24 @@ const handleUpdateSendGain = (value) => {
|
||||
updateSetting({ 'player.soundEffect.convolution.sendGain': Math.round(value) })
|
||||
}
|
||||
|
||||
const handleSetPreset = (item) => {
|
||||
updateSetting({
|
||||
'player.soundEffect.convolution.fileName': item.source,
|
||||
'player.soundEffect.convolution.mainGain': item.mainGain,
|
||||
'player.soundEffect.convolution.sendGain': item.sendGain,
|
||||
})
|
||||
}
|
||||
const userPresetList = ref([])
|
||||
const handleRemovePreset = id => {
|
||||
removeUserConvolutionPreset(id)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getUserConvolutionPresetList().then(list => {
|
||||
userPresetList.value = list
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
@@ -63,6 +87,7 @@ const handleUpdateSendGain = (value) => {
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
gap: 3px;
|
||||
min-height: 0;
|
||||
}
|
||||
.convolution {
|
||||
display: flex;
|
||||
@@ -110,4 +135,11 @@ const handleUpdateSendGain = (value) => {
|
||||
color: var(--color-primary-font);
|
||||
}
|
||||
}
|
||||
.saveList {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
margin-top: 10px;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div :class="$style.contnet">
|
||||
<div :class="$style.header">
|
||||
<h3 class="player__sound_effect_title">{{ $t('player__sound_effect_panner') }}</h3>
|
||||
<div class="player__sound_effect_title" :class="$style.header">
|
||||
<h3>{{ $t('player__sound_effect_panner') }}</h3>
|
||||
<base-checkbox
|
||||
id="player__sound_effect_panner_enabled"
|
||||
:class="$style.checkbox"
|
||||
@@ -11,16 +11,16 @@
|
||||
/>
|
||||
</div>
|
||||
<div :class="$style.eqList">
|
||||
<div :class="$style.eqItem">
|
||||
<span :class="$style.label">{{ $t('player__sound_effect_panner_sound_r') }}</span>
|
||||
<base-slider-bar :class="$style.slider" :value="appSetting['player.soundEffect.panner.soundR']" :min="1" :max="30" @change="handleUpdateSoundR" />
|
||||
<span :class="[$style.value, { [$style.active]: appSetting['player.soundEffect.panner.soundR'] != 5 }]">{{ appSetting['player.soundEffect.panner.soundR'] }}</span>
|
||||
</div>
|
||||
<div :class="$style.eqItem">
|
||||
<span :class="$style.label">{{ $t('player__sound_effect_panner_sound_speed') }}</span>
|
||||
<base-slider-bar :class="$style.slider" :value="appSetting['player.soundEffect.panner.speed']" :min="1" :max="50" @change="handleUpdateSpeed" />
|
||||
<span :class="[$style.value, { [$style.active]: appSetting['player.soundEffect.panner.speed'] != 25 }]">{{ appSetting['player.soundEffect.panner.speed'] }}</span>
|
||||
</div>
|
||||
<div :class="$style.eqItem">
|
||||
<span :class="$style.label">{{ $t('player__sound_effect_panner_sound_r') }}</span>
|
||||
<base-slider-bar :class="$style.slider" :value="appSetting['player.soundEffect.panner.soundR']" :min="1" :max="30" @change="handleUpdateSoundR" />
|
||||
<span :class="[$style.value, { [$style.active]: appSetting['player.soundEffect.panner.soundR'] != 5 }]">{{ appSetting['player.soundEffect.panner.soundR'] }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -53,9 +53,19 @@ const handleUpdateSpeed = (value) => {
|
||||
<style lang="less" module>
|
||||
@import '@renderer/assets/styles/layout.less';
|
||||
.contnet {
|
||||
padding-top: 15px;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
gap: 8px;
|
||||
&:before {
|
||||
.mixin-after;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
height: 1px;
|
||||
width: 100%;
|
||||
border-top: 1px dashed var(--color-primary-light-100-alpha-700);
|
||||
}
|
||||
}
|
||||
.header {
|
||||
display: flex;
|
||||
@@ -63,7 +73,7 @@ const handleUpdateSpeed = (value) => {
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-bottom: 5px;
|
||||
padding-top: 5px;
|
||||
// padding-top: 5px;
|
||||
}
|
||||
.eqList {
|
||||
display: flex;
|
||||
|
||||
@@ -1,16 +1,22 @@
|
||||
<template>
|
||||
<div :class="$style.contnet">
|
||||
<div :class="$style.header">
|
||||
<h3 class="player__sound_effect_title">{{ $t('player__sound_effect_biquad_filter') }}</h3>
|
||||
<div class="player__sound_effect_title" :class="$style.header">
|
||||
<h3>{{ $t('player__sound_effect_biquad_filter') }}</h3>
|
||||
<base-btn min @click="handleReset">{{ $t('player__sound_effect_biquad_filter_reset_btn') }}</base-btn>
|
||||
</div>
|
||||
<div :class="$style.eqList">
|
||||
<div v-for="(v, i) in freqs" :key="v" :class="$style.eqItem">
|
||||
<span :class="$style.label">{{ labels[i] }}</span>
|
||||
<base-slider-bar :class="$style.slider" :value="appSetting[`player.soundEffect.biquadFilter.hz${v}`]" :min="-20" :max="20" @change="handleUpdate(v, $event)" />
|
||||
<base-slider-bar :class="$style.slider" :value="appSetting[`player.soundEffect.biquadFilter.hz${v}`]" :min="-15" :max="15" @change="handleUpdate(v, $event)" />
|
||||
<span :class="$style.value">{{ appSetting[`player.soundEffect.biquadFilter.hz${v}`] }}db</span>
|
||||
</div>
|
||||
</div>
|
||||
<div :class="['scroll', $style.saveList]">
|
||||
<!-- <base-btn min @click="handleSetPreset(item)">{{ $t(`player__sound_effect_biquad_filter_preset_slow`) }}</base-btn> -->
|
||||
<base-btn v-for="item in freqsPreset" :key="item.name" min @click="handleSetPreset(item)">{{ $t(`player__sound_effect_biquad_filter_preset_${item.name}`) }}</base-btn>
|
||||
<base-btn v-for="item in userPresetList" :key="item.id" min @click="handleSetPreset(item)" @contextmenu="handleRemovePreset(item.id)">{{ item.name }}</base-btn>
|
||||
<AddEQPresetBtn />
|
||||
</div>
|
||||
<!-- <div :class="$style.footer">
|
||||
<base-btn min @click="handleReset">{{ $t('player__sound_effect_biquad_filter_reset_btn') }}</base-btn>
|
||||
</div> -->
|
||||
@@ -18,9 +24,11 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
// import { reactive } from '@common/utils/vueTools'
|
||||
import { freqs } from '@renderer/plugins/player'
|
||||
import { onMounted, ref } from '@common/utils/vueTools'
|
||||
import { freqs, freqsPreset } from '@renderer/plugins/player'
|
||||
import { appSetting, updateSetting } from '@renderer/store/setting'
|
||||
import AddEQPresetBtn from './AddEQPresetBtn'
|
||||
import { getUserEQPresetList, removeUserEQPreset } from '@renderer/store/soundEffect'
|
||||
|
||||
const labels = freqs.map(num => num < 1000 ? num : `${num / 1000}k`)
|
||||
|
||||
@@ -39,6 +47,33 @@ const handleReset = () => {
|
||||
updateSetting(setting)
|
||||
}
|
||||
|
||||
const handleSetPreset = (item) => {
|
||||
updateSetting({
|
||||
'player.soundEffect.biquadFilter.hz31': item.hz31,
|
||||
'player.soundEffect.biquadFilter.hz62': item.hz62,
|
||||
'player.soundEffect.biquadFilter.hz125': item.hz125,
|
||||
'player.soundEffect.biquadFilter.hz250': item.hz250,
|
||||
'player.soundEffect.biquadFilter.hz500': item.hz500,
|
||||
'player.soundEffect.biquadFilter.hz1000': item.hz1000,
|
||||
'player.soundEffect.biquadFilter.hz2000': item.hz2000,
|
||||
'player.soundEffect.biquadFilter.hz4000': item.hz4000,
|
||||
'player.soundEffect.biquadFilter.hz8000': item.hz8000,
|
||||
'player.soundEffect.biquadFilter.hz16000': item.hz16000,
|
||||
})
|
||||
}
|
||||
|
||||
const userPresetList = ref([])
|
||||
|
||||
const handleRemovePreset = id => {
|
||||
removeUserEQPreset(id)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getUserEQPresetList().then(list => {
|
||||
userPresetList.value = list
|
||||
})
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="less" module>
|
||||
@@ -47,6 +82,7 @@ const handleReset = () => {
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
gap: 8px;
|
||||
min-height: 0;
|
||||
}
|
||||
.header {
|
||||
display: flex;
|
||||
@@ -54,18 +90,40 @@ const handleReset = () => {
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-bottom: 5px;
|
||||
padding-top: 5px;
|
||||
// padding-top: 5px;
|
||||
}
|
||||
.eqList {
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
gap: 15px;
|
||||
flex-flow: row wrap;
|
||||
// gap: 15px;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
position: relative;
|
||||
|
||||
&:before {
|
||||
.mixin-after;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
height: 100%;
|
||||
border-left: 1px dashed var(--color-primary-light-100-alpha-700);
|
||||
}
|
||||
}
|
||||
.eqItem {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
width: 50%;
|
||||
gap: 8px;
|
||||
margin-bottom: 15px;
|
||||
box-sizing: border-box;
|
||||
&:nth-child(odd) {
|
||||
padding-right: 10px;
|
||||
}
|
||||
&:nth-child(even) {
|
||||
padding-left: 10px;
|
||||
}
|
||||
&:nth-last-child(1), &:nth-last-child(2) {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
.label {
|
||||
flex: none;
|
||||
@@ -95,4 +153,11 @@ const handleReset = () => {
|
||||
flex: auto;
|
||||
}
|
||||
|
||||
.saveList {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
margin-top: 10px;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -1,22 +1,27 @@
|
||||
<template>
|
||||
<material-popup-btn :class="$style.btnContent">
|
||||
<button :class="$style.btn" :aria-label="$t('player__sound_effect')">
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" width="90%" viewBox="0 0 24 24" space="preserve">
|
||||
<use xlink:href="#icon-tune-variant" />
|
||||
</svg>
|
||||
</button>
|
||||
<template #content>
|
||||
<div :class="$style.content">
|
||||
<button :class="$style.btn" :aria-label="$t('player__sound_effect')" @click="visible = true">
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" width="90%" viewBox="0 0 24 24" space="preserve">
|
||||
<use xlink:href="#icon-tune-variant" />
|
||||
</svg>
|
||||
</button>
|
||||
<material-modal :show="visible" bg-close="bg-close" :teleport="teleport" @close="visible = false">
|
||||
<!-- <main :class="$style.main"> -->
|
||||
<!-- <h2 :class="$style.title">{{ $t('theme_edit_modal__title') }}</h2> -->
|
||||
<div :class="$style.content">
|
||||
<div :class="$style.row">
|
||||
<AudioConvolution />
|
||||
<AudioPanner />
|
||||
</div>
|
||||
<div :class="$style.row">
|
||||
<BiquadFilter />
|
||||
</div>
|
||||
</template>
|
||||
</material-popup-btn>
|
||||
</div>
|
||||
<!-- </main> -->
|
||||
</material-modal>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
// import { reactive, ref } from '@common/utils/vueTools'
|
||||
import { ref } from '@common/utils/vueTools'
|
||||
// import useNextTogglePlay from '@renderer/utils/compositions/useNextTogglePlay'
|
||||
// import useToggleDesktopLyric from '@renderer/utils/compositions/useToggleDesktopLyric'
|
||||
// import { musicInfo, playMusicInfo } from '@renderer/store/player/state'
|
||||
@@ -27,16 +32,20 @@ import BiquadFilter from './BiquadFilter'
|
||||
import AudioPanner from './AudioPanner'
|
||||
import AudioConvolution from './AudioConvolution'
|
||||
|
||||
defineProps({
|
||||
teleport: {
|
||||
type: String,
|
||||
default: '#root',
|
||||
},
|
||||
})
|
||||
|
||||
const visible = ref(false)
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="less" module>
|
||||
@import '@renderer/assets/styles/layout.less';
|
||||
.btnContent {
|
||||
flex: none;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.btn {
|
||||
position: relative;
|
||||
// color: var(--color-button-font);
|
||||
@@ -68,12 +77,40 @@ import AudioConvolution from './AudioConvolution'
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
.main {
|
||||
min-width: 300px;
|
||||
// max-height: 100%;
|
||||
// overflow: hidden;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
padding: 5px 3px;
|
||||
gap: 15px;
|
||||
width: 400px;
|
||||
justify-content: center;
|
||||
min-height: 0;
|
||||
}
|
||||
// .title {
|
||||
// flex: none;
|
||||
// font-size: 16px;
|
||||
// color: var(--color-font);
|
||||
// line-height: 1.3;
|
||||
// text-align: center;
|
||||
// padding: 10px;
|
||||
// }
|
||||
.content {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
padding: 0 15px;
|
||||
margin: 15px 0;
|
||||
gap: 30px;
|
||||
position: relative;
|
||||
min-height: 0;
|
||||
|
||||
&:before {
|
||||
.mixin-after;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
height: 100%;
|
||||
border-left: 1px dashed var(--color-primary-light-100-alpha-700);
|
||||
}
|
||||
// width: 400px;
|
||||
|
||||
:global {
|
||||
// .player__sound_effect_contnet {
|
||||
@@ -82,10 +119,16 @@ import AudioConvolution from './AudioConvolution'
|
||||
.player__sound_effect_title {
|
||||
// margin-bottom: 10px;
|
||||
font-size: 14px;
|
||||
padding-bottom: 5px;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.row {
|
||||
width: 50%;
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
flex-flow: column nowrap;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user