Merge tag '2023.10.2' into merge-upstream
This commit is contained in:
@@ -42,6 +42,7 @@ import { useStream } from '@/stream.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { claimAchievement } from '@/scripts/achievements.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { defaultStore } from "@/store.js";
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
user: Misskey.entities.UserDetailed,
|
||||
@@ -52,6 +53,10 @@ const props = withDefaults(defineProps<{
|
||||
large: false,
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
(_: 'update:user', value: Misskey.entities.UserDetailed): void
|
||||
}>();
|
||||
|
||||
let isFollowing = $ref(props.user.isFollowing);
|
||||
let hasPendingFollowRequestFromYou = $ref(props.user.hasPendingFollowRequestFromYou);
|
||||
let wait = $ref(false);
|
||||
@@ -95,6 +100,11 @@ async function onClick() {
|
||||
} else {
|
||||
await os.api('following/create', {
|
||||
userId: props.user.id,
|
||||
withReplies: defaultStore.state.defaultWithReplies,
|
||||
});
|
||||
emit('update:user', {
|
||||
...props.user,
|
||||
withReplies: defaultStore.state.defaultWithReplies
|
||||
});
|
||||
hasPendingFollowRequestFromYou = true;
|
||||
|
||||
|
@@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
-->
|
||||
|
||||
<template>
|
||||
<div :class="[$style.root, { yellow: instance.isNotResponding, red: instance.isBlocked, gray: instance.isSuspended }]">
|
||||
<div :class="[$style.root, { yellow: instance.isNotResponding, red: instance.isBlocked, gray: instance.isSuspended, blue: instance.isSilenced }]">
|
||||
<img class="icon" :src="getInstanceIcon(instance)" alt="" loading="lazy"/>
|
||||
<div class="body">
|
||||
<span class="host">{{ instance.name ?? instance.host }}</span>
|
||||
@@ -89,6 +89,12 @@ function getInstanceIcon(instance): string {
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
&:global(.blue) {
|
||||
--c: rgba(0, 42, 255, 0.15);
|
||||
background-image: linear-gradient(45deg, var(--c) 16.67%, transparent 16.67%, transparent 50%, var(--c) 50%, var(--c) 66.67%, transparent 66.67%, transparent 100%);
|
||||
background-size: 16px 16px;
|
||||
}
|
||||
|
||||
&:global(.yellow) {
|
||||
--c: rgb(255 196 0 / 15%);
|
||||
background-image: linear-gradient(45deg, var(--c) 16.67%, transparent 16.67%, transparent 50%, var(--c) 50%, var(--c) 66.67%, transparent 66.67%, transparent 100%);
|
||||
|
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
<template>
|
||||
<MkA v-user-preview="canonical" :class="[$style.root, { [$style.isMe]: isMe }]" :to="url" :style="{ background: bgCss }">
|
||||
<img :class="$style.icon" :src="`/avatar/@${username}@${host}`" alt="">
|
||||
<img :class="$style.icon" :src="avatarUrl" alt="">
|
||||
<span>
|
||||
<span>@{{ username }}</span>
|
||||
<span v-if="(host != localHost) || defaultStore.state.showFullAcct" :class="$style.host">@{{ toUnicode(host) }}</span>
|
||||
@@ -15,11 +15,12 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { toUnicode } from 'punycode';
|
||||
import { } from 'vue';
|
||||
import { computed } from 'vue';
|
||||
import tinycolor from 'tinycolor2';
|
||||
import { host as localHost } from '@/config.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { defaultStore } from '@/store.js';
|
||||
import { getStaticImageUrl } from '@/scripts/media-proxy.js';
|
||||
|
||||
const props = defineProps<{
|
||||
username: string;
|
||||
@@ -37,6 +38,11 @@ const isMe = $i && (
|
||||
const bg = tinycolor(getComputedStyle(document.documentElement).getPropertyValue(isMe ? '--mentionMe' : '--mention'));
|
||||
bg.setAlpha(0.1);
|
||||
const bgCss = bg.toRgbString();
|
||||
|
||||
const avatarUrl = computed(() => defaultStore.state.disableShowingAnimatedImages
|
||||
? getStaticImageUrl(`/avatar/@${props.username}@${props.host}`)
|
||||
: `/avatar/@${props.username}@${props.host}`,
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" module>
|
||||
|
@@ -232,6 +232,7 @@ const keymap = {
|
||||
useNoteCapture({
|
||||
rootEl: el,
|
||||
note: $$(appearNote),
|
||||
pureNote: $$(note),
|
||||
isDeletedRef: isDeleted,
|
||||
});
|
||||
|
||||
|
@@ -94,7 +94,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<footer>
|
||||
<div :class="$style.noteFooterInfo">
|
||||
<MkA :to="notePage(appearNote)">
|
||||
<MkTime :time="appearNote.createdAt" mode="detail"/>
|
||||
<MkTime :time="appearNote.createdAt" mode="detail" colored/>
|
||||
</MkA>
|
||||
</div>
|
||||
<MkReactionsViewer ref="reactionsViewer" :note="appearNote"/>
|
||||
@@ -296,6 +296,7 @@ const reactionsPagination = $computed(() => ({
|
||||
useNoteCapture({
|
||||
rootEl: el,
|
||||
note: $$(appearNote),
|
||||
pureNote: $$(note),
|
||||
isDeletedRef: isDeleted,
|
||||
});
|
||||
|
||||
|
@@ -15,7 +15,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
</div>
|
||||
<div :class="$style.info">
|
||||
<MkA :to="notePage(note)">
|
||||
<MkTime :time="note.createdAt"/>
|
||||
<MkTime :time="note.createdAt" colored/>
|
||||
</MkA>
|
||||
<span v-if="note.visibility !== 'public'" style="margin-left: 0.5em;" :title="i18n.ts._visibility[note.visibility]">
|
||||
<i v-if="note.visibility === 'home'" class="ti ti-home"></i>
|
||||
|
@@ -283,6 +283,12 @@ useTooltip(reactionRef, (showing) => {
|
||||
|
||||
.quote:first-child {
|
||||
margin-right: 4px;
|
||||
position: relative;
|
||||
|
||||
&:before {
|
||||
position: absolute;
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
|
||||
.quote:last-child {
|
||||
|
@@ -41,7 +41,7 @@ const pagingComponent = shallowRef<InstanceType<typeof MkPagination>>();
|
||||
|
||||
const pagination: Paging = {
|
||||
endpoint: 'i/notifications' as const,
|
||||
limit: 10,
|
||||
limit: 20,
|
||||
params: computed(() => ({
|
||||
excludeTypes: props.excludeTypes ?? undefined,
|
||||
})),
|
||||
|
@@ -45,7 +45,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
</div>
|
||||
</div>
|
||||
<button class="_button" :class="$style.menu" @click="showMenu"><i class="ti ti-dots"></i></button>
|
||||
<MkFollowButton v-if="$i && user.id != $i.id" :class="$style.follow" :user="user" mini/>
|
||||
<MkFollowButton v-if="$i && user.id != $i.id" v-model:user="user" :class="$style.follow" mini/>
|
||||
</div>
|
||||
<div v-else>
|
||||
<MkLoading/>
|
||||
|
@@ -17,6 +17,7 @@ import MkSparkle from '@/components/MkSparkle.vue';
|
||||
import MkA from '@/components/global/MkA.vue';
|
||||
import { host } from '@/config.js';
|
||||
import { defaultStore } from '@/store.js';
|
||||
import { nyaize } from '@/scripts/nyaize.js';
|
||||
|
||||
const QUOTE_STYLE = `
|
||||
display: block;
|
||||
@@ -55,10 +56,13 @@ export default function(props: {
|
||||
* @param ast MFM AST
|
||||
* @param scale How times large the text is
|
||||
*/
|
||||
const genEl = (ast: mfm.MfmNode[], scale: number) => ast.map((token): VNode | string | (VNode | string)[] => {
|
||||
const genEl = (ast: mfm.MfmNode[], scale: number, disableNyaize = false) => ast.map((token): VNode | string | (VNode | string)[] => {
|
||||
switch (token.type) {
|
||||
case 'text': {
|
||||
const text = token.props.text.replace(/(\r\n|\n|\r)/g, '\n');
|
||||
let text = token.props.text.replace(/(\r\n|\n|\r)/g, '\n');
|
||||
if (!disableNyaize && props.author?.isCat) {
|
||||
text = nyaize(text);
|
||||
}
|
||||
|
||||
if (!props.plain) {
|
||||
const res: (VNode | string)[] = [];
|
||||
@@ -260,7 +264,7 @@ export default function(props: {
|
||||
key: Math.random(),
|
||||
url: token.props.url,
|
||||
rel: 'nofollow noopener',
|
||||
}, genEl(token.children, scale))];
|
||||
}, genEl(token.children, scale, true))];
|
||||
}
|
||||
|
||||
case 'mention': {
|
||||
@@ -299,11 +303,11 @@ export default function(props: {
|
||||
if (!props.nowrap) {
|
||||
return [h('div', {
|
||||
style: QUOTE_STYLE,
|
||||
}, genEl(token.children, scale))];
|
||||
}, genEl(token.children, scale, true))];
|
||||
} else {
|
||||
return [h('span', {
|
||||
style: QUOTE_STYLE,
|
||||
}, genEl(token.children, scale))];
|
||||
}, genEl(token.children, scale, true))];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -358,7 +362,7 @@ export default function(props: {
|
||||
}
|
||||
|
||||
case 'plain': {
|
||||
return [h('span', genEl(token.children, scale))];
|
||||
return [h('span', genEl(token.children, scale, true))];
|
||||
}
|
||||
|
||||
default: {
|
||||
|
@@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
-->
|
||||
|
||||
<template>
|
||||
<time :title="absolute">
|
||||
<time :title="absolute" :class="{ [$style.old1]: colored && (ago > 60 * 60 * 24 * 90), [$style.old2]: colored && (ago > 60 * 60 * 24 * 180) }">
|
||||
<template v-if="invalid">{{ i18n.ts._ago.invalid }}</template>
|
||||
<template v-else-if="mode === 'relative'">{{ relative }}</template>
|
||||
<template v-else-if="mode === 'absolute'">{{ absolute }}</template>
|
||||
@@ -22,6 +22,7 @@ const props = withDefaults(defineProps<{
|
||||
time: Date | string | number | null;
|
||||
origin?: Date | null;
|
||||
mode?: 'relative' | 'absolute' | 'detail';
|
||||
colored?: boolean;
|
||||
}>(), {
|
||||
origin: isChromatic() ? new Date('2023-04-01T00:00:00Z') : null,
|
||||
mode: 'relative',
|
||||
@@ -75,3 +76,13 @@ if (!invalid && props.origin === null && (props.mode === 'relative' || props.mod
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" module>
|
||||
.old1 {
|
||||
color: var(--warn);
|
||||
}
|
||||
|
||||
.old1.old2 {
|
||||
color: var(--error);
|
||||
}
|
||||
</style>
|
||||
|
Reference in New Issue
Block a user