summaryrefslogtreecommitdiff
path: root/packages/frontend/src
diff options
context:
space:
mode:
authorAcid Chicken (硫酸鶏) <root@acid-chicken.com>2023-04-06 08:19:49 +0900
committerGitHub <noreply@github.com>2023-04-06 08:19:49 +0900
commit3b3f683f8cdff33c8c745e1da99596e7499ca2d6 (patch)
treeb94e01d12a668cf142fa3859e965aac9174bea34 /packages/frontend/src
parentdocs: thanks (#10487) (diff)
downloadsharkey-3b3f683f8cdff33c8c745e1da99596e7499ca2d6.tar.gz
sharkey-3b3f683f8cdff33c8c745e1da99596e7499ca2d6.tar.bz2
sharkey-3b3f683f8cdff33c8c745e1da99596e7499ca2d6.zip
feat(#8149): respect nsfw settings on gallery list (#10481)
* feat(#8149): respect nsfw settings on gallery list * ci(#10336): use pull_request * test(#8149): add interaction tests * test(#10336): use `waitFor` * chore: transition
Diffstat (limited to 'packages/frontend/src')
-rw-r--r--packages/frontend/src/components/MkGalleryPostPreview.stories.impl.ts85
-rw-r--r--packages/frontend/src/components/MkGalleryPostPreview.vue39
-rw-r--r--packages/frontend/src/components/global/MkAcct.stories.impl.ts4
-rw-r--r--packages/frontend/src/components/global/MkAvatar.stories.impl.ts4
-rw-r--r--packages/frontend/src/components/global/MkUrl.stories.impl.ts6
-rw-r--r--packages/frontend/src/components/global/MkUserName.stories.impl.ts8
6 files changed, 131 insertions, 15 deletions
diff --git a/packages/frontend/src/components/MkGalleryPostPreview.stories.impl.ts b/packages/frontend/src/components/MkGalleryPostPreview.stories.impl.ts
new file mode 100644
index 0000000000..e46a708192
--- /dev/null
+++ b/packages/frontend/src/components/MkGalleryPostPreview.stories.impl.ts
@@ -0,0 +1,85 @@
+/* eslint-disable @typescript-eslint/explicit-function-return-type */
+import { expect } from '@storybook/jest';
+import { userEvent, waitFor, within } from '@storybook/testing-library';
+import { StoryObj } from '@storybook/vue3';
+import { galleryPost } from '../../.storybook/fakes';
+import MkGalleryPostPreview from './MkGalleryPostPreview.vue';
+export const Default = {
+ render(args) {
+ return {
+ components: {
+ MkGalleryPostPreview,
+ },
+ setup() {
+ return {
+ args,
+ };
+ },
+ computed: {
+ props() {
+ return {
+ ...this.args,
+ };
+ },
+ },
+ template: '<MkGalleryPostPreview v-bind="props" />',
+ };
+ },
+ async play({ canvasElement }) {
+ const canvas = within(canvasElement);
+ const links = canvas.getAllByRole('link');
+ await expect(links).toHaveLength(2);
+ await expect(links[0]).toHaveAttribute('href', `/gallery/${galleryPost().id}`);
+ await expect(links[1]).toHaveAttribute('href', `/@${galleryPost().user.username}@${galleryPost().user.host}`);
+ },
+ args: {
+ post: galleryPost(),
+ },
+ decorators: [
+ () => ({
+ template: '<div style="width:260px"><story /></div>',
+ }),
+ ],
+ parameters: {
+ layout: 'centered',
+ },
+} satisfies StoryObj<typeof MkGalleryPostPreview>;
+export const Hover = {
+ ...Default,
+ async play(context) {
+ await Default.play(context);
+ const canvas = within(context.canvasElement);
+ const links = canvas.getAllByRole('link');
+ await waitFor(() => userEvent.hover(links[0]));
+ },
+} satisfies StoryObj<typeof MkGalleryPostPreview>;
+export const HoverThenUnhover = {
+ ...Default,
+ async play(context) {
+ await Hover.play(context);
+ const canvas = within(context.canvasElement);
+ const links = canvas.getAllByRole('link');
+ await waitFor(() => userEvent.unhover(links[0]));
+ },
+} satisfies StoryObj<typeof MkGalleryPostPreview>;
+export const Sensitive = {
+ ...Default,
+ args: {
+ ...Default.args,
+ post: galleryPost(true),
+ },
+} satisfies StoryObj<typeof MkGalleryPostPreview>;
+export const SensitiveHover = {
+ ...Hover,
+ args: {
+ ...Hover.args,
+ post: galleryPost(true),
+ },
+} satisfies StoryObj<typeof MkGalleryPostPreview>;
+export const SensitiveHoverThenUnhover = {
+ ...HoverThenUnhover,
+ args: {
+ ...HoverThenUnhover.args,
+ post: galleryPost(true),
+ },
+} satisfies StoryObj<typeof MkGalleryPostPreview>;
diff --git a/packages/frontend/src/components/MkGalleryPostPreview.vue b/packages/frontend/src/components/MkGalleryPostPreview.vue
index 2c5032119f..944f5ad97b 100644
--- a/packages/frontend/src/components/MkGalleryPostPreview.vue
+++ b/packages/frontend/src/components/MkGalleryPostPreview.vue
@@ -1,7 +1,10 @@
<template>
-<MkA :to="`/gallery/${post.id}`" class="ttasepnz _panel" tabindex="-1">
+<MkA :to="`/gallery/${post.id}`" class="ttasepnz _panel" tabindex="-1" @pointerenter="enterHover" @pointerleave="leaveHover">
<div class="thumbnail">
- <ImgWithBlurhash class="img" :src="post.files[0].thumbnailUrl" :hash="post.files[0].blurhash"/>
+ <ImgWithBlurhash class="img" :hash="post.files[0].blurhash"/>
+ <Transition>
+ <ImgWithBlurhash v-if="show" class="img layered" :src="post.files[0].thumbnailUrl" :hash="post.files[0].blurhash"/>
+ </Transition>
</div>
<article>
<header>
@@ -15,12 +18,25 @@
</template>
<script lang="ts" setup>
-import { } from 'vue';
+import * as misskey from 'misskey-js';
+import { computed, ref } from 'vue';
import ImgWithBlurhash from '@/components/MkImgWithBlurhash.vue';
+import { defaultStore } from '@/store';
const props = defineProps<{
- post: any;
+ post: misskey.entities.GalleryPost;
}>();
+
+const hover = ref(false);
+const show = computed(() => defaultStore.state.nsfw === 'ignore' || defaultStore.state.nsfw === 'respect' && !props.post.isSensitive || hover.value);
+
+function enterHover(): void {
+ hover.value = true;
+}
+
+function leaveHover(): void {
+ hover.value = false;
+}
</script>
<style lang="scss" scoped>
@@ -56,6 +72,21 @@ const props = defineProps<{
width: 100%;
height: 100%;
object-fit: cover;
+
+ &.layered {
+ position: absolute;
+ top: 0;
+
+ &.v-enter-active,
+ &.v-leave-active {
+ transition: opacity 0.5s ease;
+ }
+
+ &.v-enter-from,
+ &.v-leave-to {
+ opacity: 0;
+ }
+ }
}
}
diff --git a/packages/frontend/src/components/global/MkAcct.stories.impl.ts b/packages/frontend/src/components/global/MkAcct.stories.impl.ts
index 7dfa1a14f2..d5e3fc3568 100644
--- a/packages/frontend/src/components/global/MkAcct.stories.impl.ts
+++ b/packages/frontend/src/components/global/MkAcct.stories.impl.ts
@@ -25,7 +25,7 @@ export const Default = {
},
args: {
user: {
- ...userDetailed,
+ ...userDetailed(),
host: null,
},
},
@@ -37,7 +37,7 @@ export const Detail = {
...Default,
args: {
...Default.args,
- user: userDetailed,
+ user: userDetailed(),
detail: true,
},
} satisfies StoryObj<typeof MkAcct>;
diff --git a/packages/frontend/src/components/global/MkAvatar.stories.impl.ts b/packages/frontend/src/components/global/MkAvatar.stories.impl.ts
index 6c46f75b5f..3c69c80825 100644
--- a/packages/frontend/src/components/global/MkAvatar.stories.impl.ts
+++ b/packages/frontend/src/components/global/MkAvatar.stories.impl.ts
@@ -24,7 +24,7 @@ const common = {
};
},
args: {
- user: userDetailed,
+ user: userDetailed(),
},
decorators: [
(Story, context) => ({
@@ -49,7 +49,7 @@ export const ProfilePageCat = {
args: {
...ProfilePage.args,
user: {
- ...userDetailed,
+ ...userDetailed(),
isCat: true,
},
},
diff --git a/packages/frontend/src/components/global/MkUrl.stories.impl.ts b/packages/frontend/src/components/global/MkUrl.stories.impl.ts
index 2344c4851a..c5875d4779 100644
--- a/packages/frontend/src/components/global/MkUrl.stories.impl.ts
+++ b/packages/frontend/src/components/global/MkUrl.stories.impl.ts
@@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/explicit-function-return-type */
import { expect } from '@storybook/jest';
-import { userEvent, within } from '@storybook/testing-library';
+import { userEvent, waitFor, within } from '@storybook/testing-library';
import { StoryObj } from '@storybook/vue3';
import { rest } from 'msw';
import { commonHandlers } from '../../../.storybook/mocks';
@@ -30,7 +30,7 @@ export const Default = {
const canvas = within(canvasElement);
const a = canvas.getByRole<HTMLAnchorElement>('link');
await expect(a).toHaveAttribute('href', 'https://misskey-hub.net/');
- await userEvent.hover(a);
+ await waitFor(() => userEvent.hover(a));
/*
await tick(); // FIXME: wait for network request
const anchors = canvas.getAllByRole<HTMLAnchorElement>('link');
@@ -44,7 +44,7 @@ export const Default = {
await expect(icon).toBeInTheDocument();
await expect(icon).toHaveAttribute('src', 'https://misskey-hub.net/favicon.ico');
*/
- await userEvent.unhover(a);
+ await waitFor(() => userEvent.unhover(a));
},
args: {
url: 'https://misskey-hub.net/',
diff --git a/packages/frontend/src/components/global/MkUserName.stories.impl.ts b/packages/frontend/src/components/global/MkUserName.stories.impl.ts
index 41b1567a6f..fa4f0f3b72 100644
--- a/packages/frontend/src/components/global/MkUserName.stories.impl.ts
+++ b/packages/frontend/src/components/global/MkUserName.stories.impl.ts
@@ -26,10 +26,10 @@ export const Default = {
};
},
async play({ canvasElement }) {
- await expect(canvasElement).toHaveTextContent(userDetailed.name);
+ await expect(canvasElement).toHaveTextContent(userDetailed().name);
},
args: {
- user: userDetailed,
+ user: userDetailed(),
},
parameters: {
layout: 'centered',
@@ -38,12 +38,12 @@ export const Default = {
export const Anonymous = {
...Default,
async play({ canvasElement }) {
- await expect(canvasElement).toHaveTextContent(userDetailed.username);
+ await expect(canvasElement).toHaveTextContent(userDetailed().username);
},
args: {
...Default.args,
user: {
- ...userDetailed,
+ ...userDetailed(),
name: null,
},
},