fix(frontend): #11279 adjusted margin & padding
This commit is contained in:
parent
e410b8a03b
commit
e82a2d482a
|
@ -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>
|
||||
|
|
Loading…
Reference in a new issue