Merge remote-tracking branch 'misskey-original/develop' into develop
# Conflicts: # packages/frontend/src/components/MkPostForm.vue
This commit is contained in:
commit
88122a3d9d
58 changed files with 632 additions and 175 deletions
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 &&
|
||||
|
|
|
|||
|
|
@ -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
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue