fix(frontend): #11279 adjusted margin & padding

This commit is contained in:
Yangjin Cho 2023-07-18 15:03:14 +09:00
parent e410b8a03b
commit e82a2d482a

View file

@ -1,11 +1,11 @@
<template>
<div
<div
:class="[$style.root, { [$style.modal]: modal, _popup: modal }]"
@dragover.stop="onDragover"
@dragenter="onDragenter"
@dragleave="onDragleave"
@drop.stop="onDrop"
>
>
<header :class="$style.header">
<div :class="$style.headerLeft">
<button v-if="!fixed" :class="$style.cancel" class="_button" @click="cancel"><i class="ti ti-x"></i></button>
@ -89,41 +89,41 @@
<datalist id="hashtags">
<option v-for="hashtag in recentHashtags" :key="hashtag" :value="hashtag"/>
</datalist>
</div>
</template>
</div>
</template>
<script lang="ts" setup>
import { inject, watch, nextTick, onMounted, defineAsyncComponent } from 'vue';
import * as mfm from 'mfm-js';
import * as misskey from 'misskey-js';
import insertTextAtCursor from 'insert-text-at-cursor';
import { toASCII } from 'punycode/';
import * as Acct from 'misskey-js/built/acct';
import MkNoteSimple from '@/components/MkNoteSimple.vue';
import MkNotePreview from '@/components/MkNotePreview.vue';
import XPostFormAttaches from '@/components/MkPostFormAttaches.vue';
import MkPollEditor from '@/components/MkPollEditor.vue';
import { host, url } from '@/config';
import { erase, unique } from '@/scripts/array';
import { extractMentions } from '@/scripts/extract-mentions';
import { formatTimeString } from '@/scripts/format-time-string';
import { Autocomplete } from '@/scripts/autocomplete';
import * as os from '@/os';
import { selectFiles } from '@/scripts/select-file';
import { defaultStore, notePostInterruptors, postFormActions } from '@/store';
import MkInfo from '@/components/MkInfo.vue';
import { i18n } from '@/i18n';
import { instance } from '@/instance';
import { $i, notesCount, incNotesCount, getAccounts, openAccountMenu as openAccountMenu_ } from '@/account';
import { uploadFile } from '@/scripts/upload';
import { deepClone } from '@/scripts/clone';
import MkRippleEffect from '@/components/MkRippleEffect.vue';
import { miLocalStorage } from '@/local-storage';
import { claimAchievement } from '@/scripts/achievements';
<script lang="ts" setup>
import { inject, watch, nextTick, onMounted, defineAsyncComponent } from 'vue';
import * as mfm from 'mfm-js';
import * as misskey from 'misskey-js';
import insertTextAtCursor from 'insert-text-at-cursor';
import { toASCII } from 'punycode/';
import * as Acct from 'misskey-js/built/acct';
import MkNoteSimple from '@/components/MkNoteSimple.vue';
import MkNotePreview from '@/components/MkNotePreview.vue';
import XPostFormAttaches from '@/components/MkPostFormAttaches.vue';
import MkPollEditor from '@/components/MkPollEditor.vue';
import { host, url } from '@/config';
import { erase, unique } from '@/scripts/array';
import { extractMentions } from '@/scripts/extract-mentions';
import { formatTimeString } from '@/scripts/format-time-string';
import { Autocomplete } from '@/scripts/autocomplete';
import * as os from '@/os';
import { selectFiles } from '@/scripts/select-file';
import { defaultStore, notePostInterruptors, postFormActions } from '@/store';
import MkInfo from '@/components/MkInfo.vue';
import { i18n } from '@/i18n';
import { instance } from '@/instance';
import { $i, notesCount, incNotesCount, getAccounts, openAccountMenu as openAccountMenu_ } from '@/account';
import { uploadFile } from '@/scripts/upload';
import { deepClone } from '@/scripts/clone';
import MkRippleEffect from '@/components/MkRippleEffect.vue';
import { miLocalStorage } from '@/local-storage';
import { claimAchievement } from '@/scripts/achievements';
const modal = inject('modal');
const modal = inject('modal');
const props = withDefaults(defineProps<{
const props = withDefaults(defineProps<{
reply?: misskey.entities.Note;
renote?: misskey.entities.Note;
channel?: misskey.entities.Channel; // TODO
@ -139,51 +139,51 @@ const props = withDefaults(defineProps<{
fixed?: boolean;
autofocus?: boolean;
freezeAfterPosted?: boolean;
}>(), {
}>(), {
initialVisibleUsers: () => [],
autofocus: true,
});
});
const emit = defineEmits<{
const emit = defineEmits<{
(ev: 'posted'): void;
(ev: 'cancel'): void;
(ev: 'esc'): void;
}>();
}>();
const textareaEl = $shallowRef<HTMLTextAreaElement | null>(null);
const cwInputEl = $shallowRef<HTMLInputElement | null>(null);
const hashtagsInputEl = $shallowRef<HTMLInputElement | null>(null);
const visibilityButton = $shallowRef<HTMLElement | null>(null);
const textareaEl = $shallowRef<HTMLTextAreaElement | null>(null);
const cwInputEl = $shallowRef<HTMLInputElement | null>(null);
const hashtagsInputEl = $shallowRef<HTMLInputElement | null>(null);
const visibilityButton = $shallowRef<HTMLElement | null>(null);
let posting = $ref(false);
let posted = $ref(false);
let text = $ref(props.initialText ?? '');
let files = $ref(props.initialFiles ?? []);
let poll = $ref<{
let posting = $ref(false);
let posted = $ref(false);
let text = $ref(props.initialText ?? '');
let files = $ref(props.initialFiles ?? []);
let poll = $ref<{
choices: string[];
multiple: boolean;
expiresAt: string | null;
expiredAfter: string | null;
} | null>(null);
let useCw = $ref(false);
let showPreview = $ref(false);
let cw = $ref<string | null>(null);
let localOnly = $ref<boolean>(props.initialLocalOnly ?? defaultStore.state.rememberNoteVisibility ? defaultStore.state.localOnly : defaultStore.state.defaultNoteLocalOnly);
let visibility = $ref(props.initialVisibility ?? (defaultStore.state.rememberNoteVisibility ? defaultStore.state.visibility : defaultStore.state.defaultNoteVisibility) as typeof misskey.noteVisibilities[number]);
let visibleUsers = $ref([]);
if (props.initialVisibleUsers) {
} | null>(null);
let useCw = $ref(false);
let showPreview = $ref(false);
let cw = $ref<string | null>(null);
let localOnly = $ref<boolean>(props.initialLocalOnly ?? defaultStore.state.rememberNoteVisibility ? defaultStore.state.localOnly : defaultStore.state.defaultNoteLocalOnly);
let visibility = $ref(props.initialVisibility ?? (defaultStore.state.rememberNoteVisibility ? defaultStore.state.visibility : defaultStore.state.defaultNoteVisibility) as typeof misskey.noteVisibilities[number]);
let visibleUsers = $ref([]);
if (props.initialVisibleUsers) {
props.initialVisibleUsers.forEach(pushVisibleUser);
}
let reactionAcceptance = $ref(defaultStore.state.reactionAcceptance);
let autocomplete = $ref(null);
let draghover = $ref(false);
let quoteId = $ref(null);
let hasNotSpecifiedMentions = $ref(false);
let recentHashtags = $ref(JSON.parse(miLocalStorage.getItem('hashtags') ?? '[]'));
let imeText = $ref('');
let showingOptions = $ref(false);
}
let reactionAcceptance = $ref(defaultStore.state.reactionAcceptance);
let autocomplete = $ref(null);
let draghover = $ref(false);
let quoteId = $ref(null);
let hasNotSpecifiedMentions = $ref(false);
let recentHashtags = $ref(JSON.parse(miLocalStorage.getItem('hashtags') ?? '[]'));
let imeText = $ref('');
let showingOptions = $ref(false);
const draftKey = $computed((): string => {
const draftKey = $computed((): string => {
let key = props.channel ? `channel:${props.channel.id}` : '';
if (props.renote) {
@ -195,9 +195,9 @@ const draftKey = $computed((): string => {
}
return key;
});
});
const placeholder = $computed((): string => {
const placeholder = $computed((): string => {
if (props.renote) {
return i18n.ts._postForm.quotePlaceholder;
} else if (props.reply) {
@ -215,58 +215,58 @@ const placeholder = $computed((): string => {
];
return xs[Math.floor(Math.random() * xs.length)];
}
});
});
const submitText = $computed((): string => {
const submitText = $computed((): string => {
return props.renote
? i18n.ts.quote
: props.reply
? i18n.ts.reply
: i18n.ts.note;
});
});
const textLength = $computed((): number => {
const textLength = $computed((): number => {
return (text + imeText).trim().length;
});
});
const maxTextLength = $computed((): number => {
const maxTextLength = $computed((): number => {
return instance ? instance.maxNoteTextLength : 1000;
});
});
const canPost = $computed((): boolean => {
const canPost = $computed((): boolean => {
return !posting && !posted &&
(1 <= textLength || 1 <= files.length || !!poll || !!props.renote) &&
(textLength <= maxTextLength) &&
(!poll || poll.choices.length >= 2);
});
});
const withHashtags = $computed(defaultStore.makeGetterSetter('postFormWithHashtags'));
const hashtags = $computed(defaultStore.makeGetterSetter('postFormHashtags'));
const withHashtags = $computed(defaultStore.makeGetterSetter('postFormWithHashtags'));
const hashtags = $computed(defaultStore.makeGetterSetter('postFormHashtags'));
watch($$(text), () => {
watch($$(text), () => {
checkMissingMention();
}, { immediate: true });
}, { immediate: true });
watch($$(visibility), () => {
watch($$(visibility), () => {
checkMissingMention();
}, { immediate: true });
}, { immediate: true });
watch($$(visibleUsers), () => {
watch($$(visibleUsers), () => {
checkMissingMention();
}, {
}, {
deep: true,
});
});
if (props.mention) {
if (props.mention) {
text = props.mention.host ? `@${props.mention.username}@${toASCII(props.mention.host)}` : `@${props.mention.username}`;
text += ' ';
}
}
if (props.reply && (props.reply.user.username !== $i.username || (props.reply.user.host != null && props.reply.user.host !== host))) {
if (props.reply && (props.reply.user.username !== $i.username || (props.reply.user.host != null && props.reply.user.host !== host))) {
text = `@${props.reply.user.username}${props.reply.user.host != null ? '@' + toASCII(props.reply.user.host) : ''} `;
}
}
if (props.reply && props.reply.text != null) {
if (props.reply && props.reply.text != null) {
const ast = mfm.parse(props.reply.text);
const otherHost = props.reply.user.host;
@ -285,15 +285,15 @@ if (props.reply && props.reply.text != null) {
text += `${mention} `;
}
}
}
if (props.channel) {
if (props.channel) {
visibility = 'public';
localOnly = true; // TODO:
}
}
//
if (props.reply && ['home', 'followers', 'specified'].includes(props.reply.visibility)) {
//
if (props.reply && ['home', 'followers', 'specified'].includes(props.reply.visibility)) {
if (props.reply.visibility === 'home' && visibility === 'followers') {
visibility = 'followers';
} else if (['home', 'followers'].includes(props.reply.visibility) && visibility === 'specified') {
@ -317,20 +317,20 @@ if (props.reply && ['home', 'followers', 'specified'].includes(props.reply.visib
});
}
}
}
}
if (props.specified) {
if (props.specified) {
visibility = 'specified';
pushVisibleUser(props.specified);
}
}
// keep cw when reply
if (defaultStore.state.keepCw && props.reply && props.reply.cw) {
// keep cw when reply
if (defaultStore.state.keepCw && props.reply && props.reply.cw) {
useCw = true;
cw = props.reply.cw;
}
}
function watchForDraft() {
function watchForDraft() {
watch($$(text), () => saveDraft());
watch($$(useCw), () => saveDraft());
watch($$(cw), () => saveDraft());
@ -338,9 +338,9 @@ function watchForDraft() {
watch($$(files), () => saveDraft(), { deep: true });
watch($$(visibility), () => saveDraft());
watch($$(localOnly), () => saveDraft());
}
}
function checkMissingMention() {
function checkMissingMention() {
if (visibility === 'specified') {
const ast = mfm.parse(text);
@ -352,9 +352,9 @@ function checkMissingMention() {
}
hasNotSpecifiedMentions = false;
}
}
}
function addMissingMention() {
function addMissingMention() {
const ast = mfm.parse(text);
for (const x of extractMentions(ast)) {
@ -364,9 +364,9 @@ function addMissingMention() {
});
}
}
}
}
function togglePoll() {
function togglePoll() {
if (poll) {
poll = null;
} else {
@ -377,50 +377,50 @@ function togglePoll() {
expiredAfter: null,
};
}
}
}
function addTag(tag: string) {
function addTag(tag: string) {
insertTextAtCursor(textareaEl, ` #${tag} `);
}
}
function focus() {
function focus() {
if (textareaEl) {
textareaEl.focus();
textareaEl.setSelectionRange(textareaEl.value.length, textareaEl.value.length);
}
}
}
function chooseFileFrom(ev) {
function chooseFileFrom(ev) {
selectFiles(ev.currentTarget ?? ev.target, i18n.ts.attachFile).then(files_ => {
for (const file of files_) {
files.push(file);
}
});
}
}
function detachFile(id) {
function detachFile(id) {
files = files.filter(x => x.id !== id);
}
}
function updateFileSensitive(file, sensitive) {
function updateFileSensitive(file, sensitive) {
files[files.findIndex(x => x.id === file.id)].isSensitive = sensitive;
}
}
function updateFileName(file, name) {
function updateFileName(file, name) {
files[files.findIndex(x => x.id === file.id)].name = name;
}
}
function replaceFile(file: misskey.entities.DriveFile, newFile: misskey.entities.DriveFile): void {
function replaceFile(file: misskey.entities.DriveFile, newFile: misskey.entities.DriveFile): void {
files[files.findIndex(x => x.id === file.id)] = newFile;
}
}
function upload(file: File, name?: string): void {
function upload(file: File, name?: string): void {
uploadFile(file, defaultStore.state.uploadFolder, name).then(res => {
files.push(res);
});
}
}
function setVisibility() {
function setVisibility() {
if (props.channel) {
visibility = 'public';
localOnly = true; // TODO:
@ -439,9 +439,9 @@ function setVisibility() {
}
},
}, 'closed');
}
}
async function toggleLocalOnly() {
async function toggleLocalOnly() {
if (props.channel) {
visibility = 'public';
localOnly = true; // TODO:
@ -481,9 +481,9 @@ async function toggleLocalOnly() {
}
localOnly = !localOnly;
}
}
async function toggleReactionAcceptance() {
async function toggleReactionAcceptance() {
const select = await os.select({
title: i18n.ts.reactionAcceptance,
items: [
@ -497,15 +497,15 @@ async function toggleReactionAcceptance() {
});
if (select.canceled) return;
reactionAcceptance = select.result;
}
}
function pushVisibleUser(user) {
function pushVisibleUser(user) {
if (!visibleUsers.some(u => u.username === user.username && u.host === user.host)) {
visibleUsers.push(user);
}
}
}
function addVisibleUser() {
function addVisibleUser() {
os.selectUser().then(user => {
pushVisibleUser(user);
@ -513,33 +513,33 @@ function addVisibleUser() {
text = `@${Acct.toString(user)} ${text}`;
}
});
}
}
function removeVisibleUser(user) {
function removeVisibleUser(user) {
visibleUsers = erase(user, visibleUsers);
}
}
function clear() {
function clear() {
text = '';
files = [];
poll = null;
quoteId = null;
}
}
function onKeydown(ev: KeyboardEvent) {
function onKeydown(ev: KeyboardEvent) {
if (ev.key === 'Enter' && (ev.ctrlKey || ev.metaKey) && canPost) post();
if (ev.key === 'Escape') emit('esc');
}
}
function onCompositionUpdate(ev: CompositionEvent) {
function onCompositionUpdate(ev: CompositionEvent) {
imeText = ev.data;
}
}
function onCompositionEnd(ev: CompositionEvent) {
function onCompositionEnd(ev: CompositionEvent) {
imeText = '';
}
}
async function onPaste(ev: ClipboardEvent) {
async function onPaste(ev: ClipboardEvent) {
for (const { item, i } of Array.from(ev.clipboardData.items).map((item, i) => ({ item, i }))) {
if (item.kind === 'file') {
const file = item.getAsFile();
@ -567,9 +567,9 @@ async function onPaste(ev: ClipboardEvent) {
quoteId = paste.substring(url.length).match(/^\/notes\/(.+?)\/?$/)[1];
});
}
}
}
function onDragover(ev) {
function onDragover(ev) {
if (!ev.dataTransfer.items[0]) return;
const isFile = ev.dataTransfer.items[0].kind === 'file';
const isDriveFile = ev.dataTransfer.types[0] === _DATA_TRANSFER_DRIVE_FILE_;
@ -593,17 +593,17 @@ function onDragover(ev) {
break;
}
}
}
}
function onDragenter(ev) {
function onDragenter(ev) {
draghover = true;
}
}
function onDragleave(ev) {
function onDragleave(ev) {
draghover = false;
}
}
function onDrop(ev): void {
function onDrop(ev): void {
draghover = false;
//
@ -621,9 +621,9 @@ function onDrop(ev): void {
ev.preventDefault();
}
//#endregion
}
}
function saveDraft() {
function saveDraft() {
const draftData = JSON.parse(miLocalStorage.getItem('drafts') ?? '{}');
draftData[draftKey] = {
@ -640,17 +640,17 @@ function saveDraft() {
};
miLocalStorage.setItem('drafts', JSON.stringify(draftData));
}
}
function deleteDraft() {
function deleteDraft() {
const draftData = JSON.parse(miLocalStorage.getItem('drafts') ?? '{}');
delete draftData[draftKey];
miLocalStorage.setItem('drafts', JSON.stringify(draftData));
}
}
async function post(ev?: MouseEvent) {
async function post(ev?: MouseEvent) {
if (ev) {
const el = ev.currentTarget ?? ev.target;
const rect = el.getBoundingClientRect();
@ -783,23 +783,23 @@ async function post(ev?: MouseEvent) {
text: err.message + '\n' + (err as any).id,
});
});
}
}
function cancel() {
function cancel() {
emit('cancel');
}
}
function insertMention() {
function insertMention() {
os.selectUser().then(user => {
insertTextAtCursor(textareaEl, '@' + Acct.toString(user) + ' ');
});
}
}
async function insertEmoji(ev: MouseEvent) {
async function insertEmoji(ev: MouseEvent) {
os.openEmojiPicker(ev.currentTarget ?? ev.target, {}, textareaEl);
}
}
function showActions(ev) {
function showActions(ev) {
os.popupMenu(postFormActions.map(action => ({
text: action.title,
action: () => {
@ -810,11 +810,11 @@ function showActions(ev) {
});
},
})), ev.currentTarget ?? ev.target);
}
}
let postAccount = $ref<misskey.entities.UserDetailed | null>(null);
let postAccount = $ref<misskey.entities.UserDetailed | null>(null);
function openAccountMenu(ev: MouseEvent) {
function openAccountMenu(ev: MouseEvent) {
openAccountMenu_({
withExtraOperation: false,
includeCurrentAccount: true,
@ -827,9 +827,9 @@ function openAccountMenu(ev: MouseEvent) {
}
},
}, ev);
}
}
onMounted(() => {
onMounted(() => {
if (props.autofocus) {
focus();
@ -882,15 +882,15 @@ onMounted(() => {
nextTick(() => watchForDraft());
});
});
});
defineExpose({
defineExpose({
clear,
});
</script>
});
</script>
<style lang="scss" module>
.root {
<style lang="scss" module>
.root {
position: relative;
container-type: inline-size;
@ -898,43 +898,44 @@ defineExpose({
width: 100%;
max-width: 520px;
}
}
}
//#region header
.header {
//#region header
.header {
z-index: 1000;
min-height: 50px;
display: flex;
flex-wrap: nowrap;
gap: 4px;
}
margin-bottom: -10px;
}
.headerLeft {
.headerLeft {
display: flex;
flex: 0 1 100px;
}
}
.cancel {
.cancel {
padding: 0;
font-size: 1em;
height: 100%;
flex: 0 1 50px;
}
}
.account {
.account {
height: 100%;
display: inline-flex;
vertical-align: bottom;
flex: 0 1 50px;
}
}
.avatar {
.avatar {
width: 28px;
height: 28px;
margin: auto;
}
}
.headerRight {
.headerRight {
display: flex;
min-height: 48px;
font-size: 0.9em;
@ -944,9 +945,9 @@ defineExpose({
gap: 4px;
overflow: clip;
padding-left: 4px;
}
}
.submit {
.submit {
margin: 12px 12px 12px 6px;
vertical-align: bottom;
@ -969,9 +970,9 @@ defineExpose({
background: linear-gradient(90deg, var(--X8), var(--X8));
}
}
}
}
.submitInner {
.submitInner {
padding: 0 12px;
line-height: 34px;
font-weight: bold;
@ -980,9 +981,9 @@ defineExpose({
box-sizing: border-box;
color: var(--fgOnAccent);
background: linear-gradient(90deg, var(--buttonGradateA), var(--buttonGradateB));
}
}
.headerRightItem {
.headerRightItem {
margin: 0;
padding: 8px;
border-radius: 6px;
@ -998,13 +999,13 @@ defineExpose({
&.danger {
color: #ff2a2a;
}
}
}
.headerRightButtonText {
.headerRightButtonText {
padding-left: 6px;
}
}
.visibility {
.visibility {
overflow: clip;
text-overflow: ellipsis;
white-space: nowrap;
@ -1014,51 +1015,51 @@ defineExpose({
opacity: 0.8;
}
}
}
//#endregion
}
//#endregion
.preview {
.preview {
padding: 16px 20px 0 20px;
max-height: 150px;
overflow: auto;
}
}
.targetNote {
padding: 0 20px 16px 20px;
}
.targetNote {
padding: 10px 20px 16px 20px;
}
.withQuote {
.withQuote {
margin: 0 0 8px 0;
color: var(--accent);
}
}
.toSpecified {
.toSpecified {
padding: 6px 24px;
margin-bottom: 8px;
overflow: auto;
white-space: nowrap;
}
}
.visibleUsers {
.visibleUsers {
display: inline;
top: -1px;
font-size: 14px;
}
}
.visibleUser {
.visibleUser {
margin-right: 14px;
padding: 8px 0 8px 8px;
border-radius: 8px;
background: var(--X4);
}
}
.hasNotSpecifiedMentions {
.hasNotSpecifiedMentions {
margin: 0 20px 16px 20px;
}
}
.cw,
.hashtags,
.text {
.cw,
.hashtags,
.text {
display: block;
box-sizing: border-box;
padding: 0 24px;
@ -1078,39 +1079,39 @@ defineExpose({
&:disabled {
opacity: 0.5;
}
}
}
.cw {
.cw {
z-index: 1;
padding-bottom: 8px;
border-bottom: solid 0.5px var(--divider);
}
}
.hashtags {
.hashtags {
z-index: 1;
padding-top: 8px;
padding-bottom: 8px;
border-top: solid 0.5px var(--divider);
}
}
.textOuter {
.textOuter {
width: 100%;
position: relative;
&.withCw {
padding-top: 8px;
}
}
}
.text {
.text {
max-width: 100%;
min-width: 100%;
width: 100%;
min-height: 90px;
height: 100%;
}
}
.textCount {
.textCount {
position: absolute;
top: 0;
right: 2px;
@ -1124,23 +1125,23 @@ defineExpose({
&.textOver {
color: #ff2a2a;
}
}
}
.footer {
.footer {
display: flex;
padding: 0 16px 16px 16px;
font-size: 1em;
}
}
.footerLeft {
.footerLeft {
flex: 1;
display: grid;
grid-auto-flow: row;
grid-template-columns: repeat(auto-fill, minmax(42px, 1fr));
grid-auto-rows: 40px;
}
}
.footerRight {
.footerRight {
flex: 0;
margin-left: auto;
display: grid;
@ -1148,9 +1149,9 @@ defineExpose({
grid-template-columns: repeat(auto-fill, minmax(42px, 1fr));
grid-auto-rows: 40px;
direction: rtl;
}
}
.footerButton {
.footerButton {
display: inline-block;
padding: 0;
margin: 0;
@ -1166,13 +1167,13 @@ defineExpose({
&.footerButtonActive {
color: var(--accent);
}
}
}
.previewButtonActive {
.previewButtonActive {
color: var(--accent);
}
}
@container (max-width: 500px) {
@container (max-width: 500px) {
.headerRight {
font-size: .9em;
}
@ -1209,9 +1210,9 @@ defineExpose({
.footer {
padding: 0 8px 8px 8px;
}
}
}
@container (max-width: 350px) {
@container (max-width: 350px) {
.footer {
font-size: 0.9em;
}
@ -1227,5 +1228,5 @@ defineExpose({
.headerRight {
gap: 0;
}
}
</style>
}
</style>