Merge remote-tracking branch 'misskey-original/develop' into develop

# Conflicts:
#	packages/frontend/src/components/MkPostForm.vue
This commit is contained in:
mattyatea 2024-04-14 21:54:44 +09:00
commit 88122a3d9d
58 changed files with 632 additions and 175 deletions

View file

@ -4,37 +4,59 @@ SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
<div :class="$style.root" class="_panel">
<b>{{ clip.name }}</b>
<div v-if="clip.description" :class="$style.description">{{ clip.description }}</div>
<div v-if="clip.lastClippedAt">{{ i18n.ts.updatedAt }}: <MkTime :time="clip.lastClippedAt" mode="detail"/></div>
<div :class="$style.user">
<MkAvatar :user="clip.user" :class="$style.userAvatar" indicator link preview/> <MkUserName :user="clip.user" :nowrap="false"/>
<MkA :to="`/clips/${clip.id}`" :class="$style.link">
<div :class="$style.root" class="_panel _gaps_s">
<b>{{ clip.name }}</b>
<div :class="$style.description">
<div v-if="clip.description"><Mfm :text="clip.description" :plain="true" :nowrap="true"/></div>
<div v-if="clip.lastClippedAt">{{ i18n.ts.updatedAt }}: <MkTime :time="clip.lastClippedAt" mode="detail"/></div>
<div v-if="clip.notesCount != null">{{ i18n.ts.notesCount }}: {{ number(clip.notesCount) }} / {{ $i?.policies.noteEachClipsLimit }} ({{ i18n.tsx.remainingN({ n: remaining }) }})</div>
</div>
<div :class="$style.divider"></div>
<div>
<MkAvatar :user="clip.user" :class="$style.userAvatar" indicator link preview/> <MkUserName :user="clip.user" :nowrap="false"/>
</div>
</div>
</div>
</MkA>
</template>
<script lang="ts" setup>
import * as Misskey from 'misskey-js';
import { computed } from 'vue';
import { i18n } from '@/i18n.js';
import { $i } from '@/account.js';
import number from '@/filters/number.js';
defineProps<{
clip: any;
const props = defineProps<{
clip: Misskey.entities.Clip;
}>();
const remaining = computed(() => {
return ($i?.policies && props.clip.notesCount != null) ? ($i.policies.noteEachClipsLimit - props.clip.notesCount) : i18n.ts.unknown;
});
</script>
<style lang="scss" module>
.root {
.link {
display: block;
&:hover {
text-decoration: none;
color: var(--accent);
}
}
.root {
padding: 16px;
}
.description {
padding: 8px 0;
.divider {
height: 1px;
background: var(--divider);
}
.user {
padding-top: 16px;
border-top: solid 0.5px var(--divider);
.description {
font-size: 90%;
}
.userAvatar {

View file

@ -47,12 +47,12 @@ onMounted(() => {
const width = rootEl.value!.offsetWidth;
const height = rootEl.value!.offsetHeight;
if (left + width - window.pageXOffset >= (window.innerWidth - SCROLLBAR_THICKNESS)) {
left = (window.innerWidth - SCROLLBAR_THICKNESS) - width + window.pageXOffset;
if (left + width - window.scrollX >= (window.innerWidth - SCROLLBAR_THICKNESS)) {
left = (window.innerWidth - SCROLLBAR_THICKNESS) - width + window.scrollX;
}
if (top + height - window.pageYOffset >= (window.innerHeight - SCROLLBAR_THICKNESS)) {
top = (window.innerHeight - SCROLLBAR_THICKNESS) - height + window.pageYOffset;
if (top + height - window.scrollY >= (window.innerHeight - SCROLLBAR_THICKNESS)) {
top = (window.innerHeight - SCROLLBAR_THICKNESS) - height + window.scrollY;
}
if (top < 0) {

View file

@ -165,7 +165,7 @@ function onKeydown(evt: KeyboardEvent) {
}
function onInputKeydown(evt: KeyboardEvent) {
if (evt.key === 'Enter') {
if (evt.key === 'Enter' && okButtonDisabledReason.value === null) {
evt.preventDefault();
evt.stopPropagation();
ok();

View file

@ -175,8 +175,8 @@ const align = () => {
let left;
let top;
const x = srcRect.left + (fixed.value ? 0 : window.pageXOffset);
const y = srcRect.top + (fixed.value ? 0 : window.pageYOffset);
const x = srcRect.left + (fixed.value ? 0 : window.scrollX);
const y = srcRect.top + (fixed.value ? 0 : window.scrollY);
if (props.anchor.x === 'center') {
left = x + (props.src.offsetWidth / 2) - (width / 2);
@ -220,24 +220,24 @@ const align = () => {
}
} else {
//
if (left + width - window.pageXOffset > (window.innerWidth - SCROLLBAR_THICKNESS)) {
left = (window.innerWidth - SCROLLBAR_THICKNESS) - width + window.pageXOffset - 1;
if (left + width - window.scrollX > (window.innerWidth - SCROLLBAR_THICKNESS)) {
left = (window.innerWidth - SCROLLBAR_THICKNESS) - width + window.scrollX - 1;
}
const underSpace = ((window.innerHeight - SCROLLBAR_THICKNESS) - MARGIN) - (top - window.pageYOffset);
const underSpace = ((window.innerHeight - SCROLLBAR_THICKNESS) - MARGIN) - (top - window.scrollY);
const upperSpace = (srcRect.top - MARGIN);
//
if (top + height - window.pageYOffset > ((window.innerHeight - SCROLLBAR_THICKNESS) - MARGIN)) {
if (top + height - window.scrollY > ((window.innerHeight - SCROLLBAR_THICKNESS) - MARGIN)) {
if (props.noOverlap && props.anchor.x === 'center') {
if (underSpace >= (upperSpace / 3)) {
maxHeight.value = underSpace;
} else {
maxHeight.value = upperSpace;
top = window.pageYOffset + ((upperSpace + MARGIN) - height);
top = window.scrollY + ((upperSpace + MARGIN) - height);
}
} else {
top = ((window.innerHeight - SCROLLBAR_THICKNESS) - MARGIN) - height + window.pageYOffset - 1;
top = ((window.innerHeight - SCROLLBAR_THICKNESS) - MARGIN) - height + window.scrollY - 1;
}
} else {
maxHeight.value = underSpace;
@ -255,15 +255,15 @@ const align = () => {
let transformOriginX = 'center';
let transformOriginY = 'center';
if (top >= srcRect.top + props.src.offsetHeight + (fixed.value ? 0 : window.pageYOffset)) {
if (top >= srcRect.top + props.src.offsetHeight + (fixed.value ? 0 : window.scrollY)) {
transformOriginY = 'top';
} else if ((top + height) <= srcRect.top + (fixed.value ? 0 : window.pageYOffset)) {
} else if ((top + height) <= srcRect.top + (fixed.value ? 0 : window.scrollY)) {
transformOriginY = 'bottom';
}
if (left >= srcRect.left + props.src.offsetWidth + (fixed.value ? 0 : window.pageXOffset)) {
if (left >= srcRect.left + props.src.offsetWidth + (fixed.value ? 0 : window.scrollX)) {
transformOriginX = 'left';
} else if ((left + width) <= srcRect.left + (fixed.value ? 0 : window.pageXOffset)) {
} else if ((left + width) <= srcRect.left + (fixed.value ? 0 : window.scrollX)) {
transformOriginX = 'right';
}

View file

@ -249,6 +249,7 @@ if (noteViewInterruptors.length > 0) {
const isRenote = (
note.value.renote != null &&
note.value.reply == null &&
note.value.text == null &&
note.value.cw == null &&
note.value.fileIds && note.value.fileIds.length === 0 &&

View file

@ -68,7 +68,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div :class="$style.noteContent">
<p v-if="appearNote.cw != null" :class="$style.cw">
<Mfm v-if="appearNote.cw != ''" style="margin-right: 8px;" :text="appearNote.cw" :author="appearNote.user" :nyaize="'respect'"/>
<MkCwButton v-model="showContent" :text="appearNote.text" :files="appearNote.files" :poll="appearNote.poll"/>
<MkCwButton v-model="showContent" :text="appearNote.text" :renote="appearNote.renote" :files="appearNote.files" :poll="appearNote.poll"/>
</p>
<div v-show="appearNote.cw == null || showContent">
<span v-if="appearNote.isHidden" style="opacity: 0.5">({{ i18n.ts.private }})</span>
@ -328,7 +328,9 @@ if (noteViewInterruptors.length > 0) {
const isRenote = (
note.value.renote != null &&
note.value.reply == null &&
note.value.text == null &&
note.value.cw == null &&
note.value.fileIds && note.value.fileIds.length === 0 &&
note.value.poll == null
);

View file

@ -272,7 +272,13 @@ const maxTextLength = computed((): number => {
const canPost = computed((): boolean => {
return !props.mock && !posting.value && !posted.value &&
(1 <= textLength.value || 1 <= files.value.length || !!poll.value || !!props.renote) &&
(
1 <= textLength.value ||
1 <= files.value.length ||
poll.value != null ||
props.renote != null ||
(props.reply != null && quoteId.value != null)
) &&
(textLength.value <= maxTextLength.value) &&
(!poll.value || poll.value.choices.length >= 2);
});

View file

@ -33,8 +33,8 @@ const left = ref(0);
onMounted(() => {
const rect = props.source.getBoundingClientRect();
const x = Math.max((rect.left + (props.source.offsetWidth / 2)) - (300 / 2), 6) + window.pageXOffset;
const y = rect.top + props.source.offsetHeight + window.pageYOffset;
const x = Math.max((rect.left + (props.source.offsetWidth / 2)) - (300 / 2), 6) + window.scrollX;
const y = rect.top + props.source.offsetHeight + window.scrollY;
top.value = y;
left.value = x;

View file

@ -106,8 +106,8 @@ onMounted(() => {
}
const rect = props.source.getBoundingClientRect();
const x = ((rect.left + (props.source.offsetWidth / 2)) - (300 / 2)) + window.pageXOffset;
const y = rect.top + props.source.offsetHeight + window.pageYOffset;
const x = ((rect.left + (props.source.offsetWidth / 2)) - (300 / 2)) + window.scrollX;
const y = rect.top + props.source.offsetHeight + window.scrollY;
top.value = y;
left.value = x;

View file

@ -47,7 +47,7 @@ const invalid = Number.isNaN(_time);
const absolute = !invalid ? dateTimeFormat.format(_time) : i18n.ts._ago.invalid;
// eslint-disable-next-line vue/no-setup-props-destructure
const now = ref((props.origin ?? new Date()).getTime());
const now = ref(props.origin?.getTime() ?? Date.now());
const ago = computed(() => (now.value - _time) / 1000/*ms*/);
const relative = computed<string>(() => {
@ -77,7 +77,7 @@ let tickId: number;
let currentInterval: number;
function tick() {
now.value = (new Date()).getTime();
now.value = Date.now();
const nextInterval = ago.value < 60 ? 10000 : ago.value < 3600 ? 60000 : 180000;
if (currentInterval !== nextInterval) {