From 9bb6c536c0cdf6c5fa5e9bda7ceba36f007ef4eb Mon Sep 17 00:00:00 2001 From: "Acid Chicken (硫酸鶏)" Date: Thu, 13 Apr 2023 12:20:39 +0900 Subject: test(#10336): add `components/Mk[A-B].*` stories (#10475) * chore(#10336): register snippets * test(#10336): add `components/Mk[A-B].*` stories * build: desynced lockfile * ci(#10336): preload assets * ci(#10336): use pull_request * build: update lockfile * fix: reactivity transform * chore: track upstream changes * refactor: avoid temporary previous tapping declarations * revert: avoid temporary previous tapping declarations This reverts commit e649b1b1e6771bee674f2dfb044e0efd72d0be5d. * test: flaky snapshots * style: import --- .../src/components/MkAbuseReport.stories.impl.ts | 49 ++++++ .../components/MkAbuseReportWindow.stories.impl.ts | 49 ++++++ .../src/components/MkAccountMoved.stories.impl.ts | 33 ++++ .../frontend/src/components/MkAccountMoved.vue | 4 +- .../src/components/MkAchievements.stories.impl.ts | 56 +++++++ .../src/components/MkAnalogClock.stories.impl.ts | 9 ++ packages/frontend/src/components/MkAnalogClock.vue | 12 +- .../frontend/src/components/MkAsUi.stories.impl.ts | 2 + .../src/components/MkAutocomplete.stories.impl.ts | 176 +++++++++++++++++++++ .../src/components/MkAvatars.stories.impl.ts | 46 ++++++ .../src/components/MkButton.stories.impl.ts | 53 ++++++- .../src/components/global/MkError.stories.impl.ts | 10 +- packages/frontend/src/components/global/MkTime.vue | 3 +- 13 files changed, 494 insertions(+), 8 deletions(-) create mode 100644 packages/frontend/src/components/MkAbuseReport.stories.impl.ts create mode 100644 packages/frontend/src/components/MkAbuseReportWindow.stories.impl.ts create mode 100644 packages/frontend/src/components/MkAccountMoved.stories.impl.ts create mode 100644 packages/frontend/src/components/MkAchievements.stories.impl.ts create mode 100644 packages/frontend/src/components/MkAsUi.stories.impl.ts create mode 100644 packages/frontend/src/components/MkAutocomplete.stories.impl.ts create mode 100644 packages/frontend/src/components/MkAvatars.stories.impl.ts (limited to 'packages/frontend/src/components') diff --git a/packages/frontend/src/components/MkAbuseReport.stories.impl.ts b/packages/frontend/src/components/MkAbuseReport.stories.impl.ts new file mode 100644 index 0000000000..7d27adeb04 --- /dev/null +++ b/packages/frontend/src/components/MkAbuseReport.stories.impl.ts @@ -0,0 +1,49 @@ +/* eslint-disable @typescript-eslint/explicit-function-return-type */ +import { action } from '@storybook/addon-actions'; +import { StoryObj } from '@storybook/vue3'; +import { rest } from 'msw'; +import { abuseUserReport } from '../../.storybook/fakes'; +import { commonHandlers } from '../../.storybook/mocks'; +import MkAbuseReport from './MkAbuseReport.vue'; +export const Default = { + render(args) { + return { + components: { + MkAbuseReport, + }, + setup() { + return { + args, + }; + }, + computed: { + props() { + return { + ...this.args, + }; + }, + events() { + return { + resolved: action('resolved'), + }; + }, + }, + template: '', + }; + }, + args: { + report: abuseUserReport(), + }, + parameters: { + layout: 'fullscreen', + msw: { + handlers: [ + ...commonHandlers, + rest.post('/api/admin/resolve-abuse-user-report', async (req, res, ctx) => { + action('POST /api/admin/resolve-abuse-user-report')(await req.json()); + return res(ctx.json({})); + }), + ], + }, + }, +} satisfies StoryObj; diff --git a/packages/frontend/src/components/MkAbuseReportWindow.stories.impl.ts b/packages/frontend/src/components/MkAbuseReportWindow.stories.impl.ts new file mode 100644 index 0000000000..d0877ffd3b --- /dev/null +++ b/packages/frontend/src/components/MkAbuseReportWindow.stories.impl.ts @@ -0,0 +1,49 @@ +/* eslint-disable @typescript-eslint/explicit-function-return-type */ +import { action } from '@storybook/addon-actions'; +import { StoryObj } from '@storybook/vue3'; +import { rest } from 'msw'; +import { userDetailed } from '../../.storybook/fakes'; +import { commonHandlers } from '../../.storybook/mocks'; +import MkAbuseReportWindow from './MkAbuseReportWindow.vue'; +export const Default = { + render(args) { + return { + components: { + MkAbuseReportWindow, + }, + setup() { + return { + args, + }; + }, + computed: { + props() { + return { + ...this.args, + }; + }, + events() { + return { + 'closed': action('closed'), + }; + }, + }, + template: '', + }; + }, + args: { + user: userDetailed(), + }, + parameters: { + layout: 'centered', + msw: { + handlers: [ + ...commonHandlers, + rest.post('/api/users/report-abuse', async (req, res, ctx) => { + action('POST /api/users/report-abuse')(await req.json()); + return res(ctx.json({})); + }), + ], + }, + }, +} satisfies StoryObj; diff --git a/packages/frontend/src/components/MkAccountMoved.stories.impl.ts b/packages/frontend/src/components/MkAccountMoved.stories.impl.ts new file mode 100644 index 0000000000..bed9d94311 --- /dev/null +++ b/packages/frontend/src/components/MkAccountMoved.stories.impl.ts @@ -0,0 +1,33 @@ +/* eslint-disable @typescript-eslint/explicit-function-return-type */ +import { StoryObj } from '@storybook/vue3'; +import { userDetailed } from '../../.storybook/fakes'; +import MkAccountMoved from './MkAccountMoved.vue'; +export const Default = { + render(args) { + return { + components: { + MkAccountMoved, + }, + setup() { + return { + args, + }; + }, + computed: { + props() { + return { + ...this.args, + }; + }, + }, + template: '', + }; + }, + args: { + username: userDetailed().username, + host: userDetailed().host, + }, + parameters: { + layout: 'centered', + }, +} satisfies StoryObj; diff --git a/packages/frontend/src/components/MkAccountMoved.vue b/packages/frontend/src/components/MkAccountMoved.vue index fd472de6c1..98979de236 100644 --- a/packages/frontend/src/components/MkAccountMoved.vue +++ b/packages/frontend/src/components/MkAccountMoved.vue @@ -2,7 +2,7 @@
{{ i18n.ts.accountMoved }} - +
@@ -12,7 +12,7 @@ import { i18n } from '@/i18n'; import { host as localHost } from '@/config'; defineProps<{ - acct: string; + username: string; host: string; }>(); diff --git a/packages/frontend/src/components/MkAchievements.stories.impl.ts b/packages/frontend/src/components/MkAchievements.stories.impl.ts new file mode 100644 index 0000000000..477152a47b --- /dev/null +++ b/packages/frontend/src/components/MkAchievements.stories.impl.ts @@ -0,0 +1,56 @@ +/* eslint-disable @typescript-eslint/explicit-function-return-type */ +import { StoryObj } from '@storybook/vue3'; +import { rest } from 'msw'; +import { userDetailed } from '../../.storybook/fakes'; +import { commonHandlers } from '../../.storybook/mocks'; +import MkAchievements from './MkAchievements.vue'; +import { ACHIEVEMENT_TYPES } from '@/scripts/achievements'; +export const Empty = { + render(args) { + return { + components: { + MkAchievements, + }, + setup() { + return { + args, + }; + }, + computed: { + props() { + return { + ...this.args, + }; + }, + }, + template: '', + }; + }, + args: { + user: userDetailed(), + }, + parameters: { + layout: 'fullscreen', + msw: { + handlers: [ + ...commonHandlers, + rest.post('/api/users/achievements', (req, res, ctx) => { + return res(ctx.json([])); + }), + ], + }, + }, +} satisfies StoryObj; +export const All = { + ...Empty, + parameters: { + msw: { + handlers: [ + ...commonHandlers, + rest.post('/api/users/achievements', (req, res, ctx) => { + return res(ctx.json(ACHIEVEMENT_TYPES.map((name) => ({ name, unlockedAt: 0 })))); + }), + ], + }, + }, +} satisfies StoryObj; diff --git a/packages/frontend/src/components/MkAnalogClock.stories.impl.ts b/packages/frontend/src/components/MkAnalogClock.stories.impl.ts index 05190aa268..e7fbb47284 100644 --- a/packages/frontend/src/components/MkAnalogClock.stories.impl.ts +++ b/packages/frontend/src/components/MkAnalogClock.stories.impl.ts @@ -1,6 +1,7 @@ /* eslint-disable @typescript-eslint/explicit-function-return-type */ import { StoryObj } from '@storybook/vue3'; import MkAnalogClock from './MkAnalogClock.vue'; +import isChromatic from 'chromatic'; export const Default = { render(args) { return { @@ -22,6 +23,14 @@ export const Default = { template: '', }; }, + args: { + now: isChromatic() ? () => new Date('2023-01-01T10:10:30') : undefined, + }, + decorators: [ + () => ({ + template: '
', + }), + ], parameters: { layout: 'fullscreen', }, diff --git a/packages/frontend/src/components/MkAnalogClock.vue b/packages/frontend/src/components/MkAnalogClock.vue index 1218202616..f12020f810 100644 --- a/packages/frontend/src/components/MkAnalogClock.vue +++ b/packages/frontend/src/components/MkAnalogClock.vue @@ -99,6 +99,7 @@ const props = withDefaults(defineProps<{ graduations?: 'none' | 'dots' | 'numbers'; fadeGraduations?: boolean; sAnimation?: 'none' | 'elastic' | 'easeOut'; + now?: () => Date; }>(), { numbers: false, thickness: 0.1, @@ -107,6 +108,7 @@ const props = withDefaults(defineProps<{ graduations: 'dots', fadeGraduations: true, sAnimation: 'elastic', + now: () => new Date(), }); const graduationsMajor = computed(() => { @@ -145,11 +147,17 @@ let disableSAnimate = $ref(false); let sOneRound = false; function tick() { - const now = new Date(); - now.setMinutes(now.getMinutes() + (new Date().getTimezoneOffset() + props.offset)); + const now = props.now(); + now.setMinutes(now.getMinutes() + now.getTimezoneOffset() + props.offset); + const previousS = s; + const previousM = m; + const previousH = h; s = now.getSeconds(); m = now.getMinutes(); h = now.getHours(); + if (previousS === s && previousM === m && previousH === h) { + return; + } hAngle = Math.PI * (h % (props.twentyfour ? 24 : 12) + (m + s / 60) / 60) / (props.twentyfour ? 12 : 6); mAngle = Math.PI * (m + s / 60) / 30; if (sOneRound) { // 秒針が一周した際のアニメーションをよしなに処理する(これが無いと秒が59->0になったときに期待したアニメーションにならない) diff --git a/packages/frontend/src/components/MkAsUi.stories.impl.ts b/packages/frontend/src/components/MkAsUi.stories.impl.ts new file mode 100644 index 0000000000..b67c0e679d --- /dev/null +++ b/packages/frontend/src/components/MkAsUi.stories.impl.ts @@ -0,0 +1,2 @@ +import MkAsUi from './MkAsUi.vue'; +void MkAsUi; diff --git a/packages/frontend/src/components/MkAutocomplete.stories.impl.ts b/packages/frontend/src/components/MkAutocomplete.stories.impl.ts new file mode 100644 index 0000000000..075904d6a3 --- /dev/null +++ b/packages/frontend/src/components/MkAutocomplete.stories.impl.ts @@ -0,0 +1,176 @@ +/* eslint-disable @typescript-eslint/explicit-function-return-type */ +import { action } from '@storybook/addon-actions'; +import { expect } from '@storybook/jest'; +import { userEvent, waitFor, within } from '@storybook/testing-library'; +import { StoryObj } from '@storybook/vue3'; +import { rest } from 'msw'; +import { userDetailed } from '../../.storybook/fakes'; +import { commonHandlers } from '../../.storybook/mocks'; +import MkAutocomplete from './MkAutocomplete.vue'; +import MkInput from './MkInput.vue'; +import { tick } from '@/scripts/test-utils'; +const common = { + render(args) { + return { + components: { + MkAutocomplete, + }, + setup() { + return { + args, + }; + }, + computed: { + props() { + return { + ...this.args, + }; + }, + events() { + return { + open: action('open'), + closed: action('closed'), + }; + }, + }, + template: '', + }; + }, + args: { + close: action('close'), + x: 0, + y: 0, + }, + decorators: [ + (_, context) => ({ + components: { + MkInput, + }, + data() { + return { + q: context.args.q, + textarea: null, + }; + }, + methods: { + inputMounted() { + this.textarea = this.$refs.input.$refs.inputEl; + }, + }, + template: '', + }), + ], + parameters: { + controls: { + exclude: ['textarea'], + }, + layout: 'centered', + chromatic: { + // FIXME: flaky + disableSnapshot: true, + }, + }, +} satisfies StoryObj; +export const User = { + ...common, + args: { + ...common.args, + type: 'user', + }, + async play({ canvasElement }) { + const canvas = within(canvasElement); + const input = canvas.getByRole('combobox'); + await waitFor(() => userEvent.hover(input)); + await waitFor(() => userEvent.click(input)); + await waitFor(() => userEvent.type(input, 'm')); + await waitFor(async () => { + await userEvent.type(input, ' ', { delay: 256 }); + await tick(); + return await expect(canvas.getByRole('list')).toBeInTheDocument(); + }, { timeout: 16384 }); + }, + parameters: { + ...common.parameters, + msw: { + handlers: [ + ...commonHandlers, + rest.post('/api/users/search-by-username-and-host', (req, res, ctx) => { + return res(ctx.json([ + userDetailed('44', 'mizuki', 'misskey-hub.net', 'Mizuki'), + userDetailed('49', 'momoko', 'misskey-hub.net', 'Momoko'), + ])); + }), + ], + }, + }, +}; +export const Hashtag = { + ...common, + args: { + ...common.args, + type: 'hashtag', + }, + async play({ canvasElement }) { + const canvas = within(canvasElement); + const input = canvas.getByRole('combobox'); + await waitFor(() => userEvent.hover(input)); + await waitFor(() => userEvent.click(input)); + await waitFor(() => userEvent.type(input, '気象')); + await waitFor(async () => { + await userEvent.type(input, ' ', { delay: 256 }); + await tick(); + return await expect(canvas.getByRole('list')).toBeInTheDocument(); + }, { interval: 256, timeout: 16384 }); + }, + parameters: { + ...common.parameters, + msw: { + handlers: [ + ...commonHandlers, + rest.post('/api/hashtags/search', (req, res, ctx) => { + return res(ctx.json([ + '気象警報注意報', + '気象警報', + '気象情報', + ])); + }), + ], + }, + }, +}; +export const Emoji = { + ...common, + args: { + ...common.args, + type: 'emoji', + }, + async play({ canvasElement }) { + const canvas = within(canvasElement); + const input = canvas.getByRole('combobox'); + await waitFor(() => userEvent.hover(input)); + await waitFor(() => userEvent.click(input)); + await waitFor(() => userEvent.type(input, 'smile')); + await waitFor(async () => { + await userEvent.type(input, ' ', { delay: 256 }); + await tick(); + return await expect(canvas.getByRole('list')).toBeInTheDocument(); + }, { interval: 256, timeout: 16384 }); + }, +} satisfies StoryObj; +export const MfmTag = { + ...common, + args: { + ...common.args, + type: 'mfmTag', + }, + async play({ canvasElement }) { + const canvas = within(canvasElement); + const input = canvas.getByRole('combobox'); + await waitFor(() => userEvent.hover(input)); + await waitFor(() => userEvent.click(input)); + await waitFor(async () => { + await tick(); + return await expect(canvas.getByRole('list')).toBeInTheDocument(); + }, { interval: 256, timeout: 16384 }); + }, +} satisfies StoryObj; diff --git a/packages/frontend/src/components/MkAvatars.stories.impl.ts b/packages/frontend/src/components/MkAvatars.stories.impl.ts new file mode 100644 index 0000000000..14052c7343 --- /dev/null +++ b/packages/frontend/src/components/MkAvatars.stories.impl.ts @@ -0,0 +1,46 @@ +/* eslint-disable @typescript-eslint/explicit-function-return-type */ +import { StoryObj } from '@storybook/vue3'; +import { rest } from 'msw'; +import { userDetailed } from '../../.storybook/fakes'; +import { commonHandlers } from '../../.storybook/mocks'; +import MkAvatars from './MkAvatars.vue'; +export const Default = { + render(args) { + return { + components: { + MkAvatars, + }, + setup() { + return { + args, + }; + }, + computed: { + props() { + return { + ...this.args, + }; + }, + }, + template: '', + }; + }, + args: { + userIds: ['17', '20', '18'], + }, + parameters: { + layout: 'centered', + msw: { + handlers: [ + ...commonHandlers, + rest.post('/api/users/show', (req, res, ctx) => { + return res(ctx.json([ + userDetailed('17'), + userDetailed('20'), + userDetailed('18'), + ])); + }), + ], + }, + }, +} satisfies StoryObj; diff --git a/packages/frontend/src/components/MkButton.stories.impl.ts b/packages/frontend/src/components/MkButton.stories.impl.ts index e1c1c54d10..982a8b3be1 100644 --- a/packages/frontend/src/components/MkButton.stories.impl.ts +++ b/packages/frontend/src/components/MkButton.stories.impl.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/explicit-function-return-type */ /* eslint-disable import/no-default-export */ -/* eslint-disable import/no-duplicates */ +import { action } from '@storybook/addon-actions'; import { StoryObj } from '@storybook/vue3'; import MkButton from './MkButton.vue'; export const Default = { @@ -20,11 +20,60 @@ export const Default = { ...this.args, }; }, + events() { + return { + click: action('click'), + }; + }, }, - template: 'Text', + template: 'Text', }; }, + args: { + }, parameters: { layout: 'centered', }, } satisfies StoryObj; +export const Primary = { + ...Default, + args: { + ...Default.args, + primary: true, + }, +} satisfies StoryObj; +export const Gradate = { + ...Default, + args: { + ...Default.args, + gradate: true, + }, +} satisfies StoryObj; +export const Rounded = { + ...Default, + args: { + ...Default.args, + rounded: true, + }, +} satisfies StoryObj; +export const Danger = { + ...Default, + args: { + ...Default.args, + danger: true, + }, +} satisfies StoryObj; +export const Small = { + ...Default, + args: { + ...Default.args, + small: true, + }, +} satisfies StoryObj; +export const Large = { + ...Default, + args: { + ...Default.args, + large: true, + }, +} satisfies StoryObj; diff --git a/packages/frontend/src/components/global/MkError.stories.impl.ts b/packages/frontend/src/components/global/MkError.stories.impl.ts index 60ac5c91ad..8252a4d76e 100644 --- a/packages/frontend/src/components/global/MkError.stories.impl.ts +++ b/packages/frontend/src/components/global/MkError.stories.impl.ts @@ -1,4 +1,5 @@ /* eslint-disable @typescript-eslint/explicit-function-return-type */ +import { action } from '@storybook/addon-actions'; import { expect } from '@storybook/jest'; import { waitFor } from '@storybook/testing-library'; import { StoryObj } from '@storybook/vue3'; @@ -20,14 +21,21 @@ export const Default = { ...this.args, }; }, + events() { + return { + retry: action('retry'), + }; + }, }, - template: '', + template: '', }; }, async play({ canvasElement }) { await expect(canvasElement.firstElementChild).not.toBeNull(); await waitFor(async () => expect(canvasElement.firstElementChild?.classList).not.toContain('_transition_zoom-enter-active')); }, + args: { + }, parameters: { layout: 'centered', }, diff --git a/packages/frontend/src/components/global/MkTime.vue b/packages/frontend/src/components/global/MkTime.vue index 99169512db..261cc0ee18 100644 --- a/packages/frontend/src/components/global/MkTime.vue +++ b/packages/frontend/src/components/global/MkTime.vue @@ -8,6 +8,7 @@ diff --git a/packages/frontend/src/components/MkSignupDialog.form.vue b/packages/frontend/src/components/MkSignupDialog.form.vue new file mode 100644 index 0000000000..0e8bdb321e --- /dev/null +++ b/packages/frontend/src/components/MkSignupDialog.form.vue @@ -0,0 +1,272 @@ + + + + + diff --git a/packages/frontend/src/components/MkSignupDialog.rules.stories.impl.ts b/packages/frontend/src/components/MkSignupDialog.rules.stories.impl.ts new file mode 100644 index 0000000000..1308dfff9a --- /dev/null +++ b/packages/frontend/src/components/MkSignupDialog.rules.stories.impl.ts @@ -0,0 +1,94 @@ +/* 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 { onBeforeUnmount } from 'vue'; +import MkSignupServerRules from './MkSignupDialog,rules.vue'; +import { i18n } from '@/i18n'; +import { instance } from '@/instance'; +export const Empty = { + render(args) { + return { + components: { + MkSignupServerRules, + }, + setup() { + return { + args, + }; + }, + computed: { + props() { + return { + ...this.args, + }; + }, + }, + template: '', + }; + }, + async play({ canvasElement }) { + const canvas = within(canvasElement); + const groups = await canvas.findAllByRole('group'); + const buttons = await canvas.findAllByRole('button'); + for (const group of groups) { + if (group.ariaExpanded === 'true') { + continue; + } + const button = await within(group).findByRole('button'); + userEvent.click(button); + await waitFor(() => expect(group).toHaveAttribute('aria-expanded', 'true')); + } + const labels = await canvas.findAllByText(i18n.ts.agree); + for (const label of labels) { + expect(buttons.at(-1)).toBeDisabled(); + await waitFor(() => userEvent.click(label)); + } + expect(buttons.at(-1)).toBeEnabled(); + }, + args: { + serverRules: [], + tosUrl: null, + }, + decorators: [ + (_, context) => ({ + setup() { + instance.serverRules = context.args.serverRules; + instance.tosUrl = context.args.tosUrl; + onBeforeUnmount(() => { + // FIXME: 呼び出されない + instance.serverRules = []; + instance.tosUrl = null; + }); + }, + template: '', + }), + ], + parameters: { + layout: 'centered', + }, +} satisfies StoryObj; +export const ServerRulesOnly = { + ...Empty, + args: { + ...Empty.args, + serverRules: [ + 'ルール', + ], + }, +} satisfies StoryObj; +export const TOSOnly = { + ...Empty, + args: { + ...Empty.args, + tosUrl: 'https://example.com/tos', + }, +} satisfies StoryObj; +export const ServerRulesAndTOS = { + ...Empty, + args: { + ...Empty.args, + serverRules: ServerRulesOnly.args.serverRules, + tosUrl: TOSOnly.args.tosUrl, + }, +} satisfies StoryObj; diff --git a/packages/frontend/src/components/MkSignupDialog.rules.vue b/packages/frontend/src/components/MkSignupDialog.rules.vue new file mode 100644 index 0000000000..be1c7f8c35 --- /dev/null +++ b/packages/frontend/src/components/MkSignupDialog.rules.vue @@ -0,0 +1,114 @@ + + + + + diff --git a/packages/frontend/src/components/MkSignupDialog.vue b/packages/frontend/src/components/MkSignupDialog.vue index 790c1e94df..b4fc564d36 100644 --- a/packages/frontend/src/components/MkSignupDialog.vue +++ b/packages/frontend/src/components/MkSignupDialog.vue @@ -1,24 +1,40 @@ + + diff --git a/packages/frontend/src/components/MkSwitch.vue b/packages/frontend/src/components/MkSwitch.vue index 8bb8637dda..d9f6716f92 100644 --- a/packages/frontend/src/components/MkSwitch.vue +++ b/packages/frontend/src/components/MkSwitch.vue @@ -9,7 +9,7 @@ :disabled="disabled" @keydown.enter="toggle" > - +
diff --git a/packages/frontend/src/pages/about.vue b/packages/frontend/src/pages/about.vue index d54d93eaee..1ca5ba6ca7 100644 --- a/packages/frontend/src/pages/about.vue +++ b/packages/frontend/src/pages/about.vue @@ -41,7 +41,7 @@ - {{ i18n.ts.tos }} + {{ i18n.ts.termsOfService }} diff --git a/packages/frontend/src/pages/admin/moderation.vue b/packages/frontend/src/pages/admin/moderation.vue index ebe1a8ade0..e7e3cb5368 100644 --- a/packages/frontend/src/pages/admin/moderation.vue +++ b/packages/frontend/src/pages/admin/moderation.vue @@ -3,10 +3,15 @@ + {{ i18n.ts.serverRules }}
+ + + + @@ -41,16 +46,20 @@ import { fetchInstance } from '@/instance'; import { i18n } from '@/i18n'; import { definePageMetadata } from '@/scripts/page-metadata'; import MkButton from '@/components/MkButton.vue'; +import FormLink from "@/components/form/link.vue"; let sensitiveWords: string = $ref(''); +let tosUrl: string | null = $ref(null); async function init() { const meta = await os.api('admin/meta'); sensitiveWords = meta.sensitiveWords.join('\n'); + tosUrl = meta.tosUrl; } function save() { os.apiWithDialog('admin/update-meta', { + tosUrl, sensitiveWords: sensitiveWords.split('\n'), }).then(() => { fetchInstance(); diff --git a/packages/frontend/src/pages/admin/server-rules.vue b/packages/frontend/src/pages/admin/server-rules.vue new file mode 100644 index 0000000000..85781c0bd0 --- /dev/null +++ b/packages/frontend/src/pages/admin/server-rules.vue @@ -0,0 +1,128 @@ + + + + + diff --git a/packages/frontend/src/pages/admin/settings.vue b/packages/frontend/src/pages/admin/settings.vue index 65e64930d5..e9de6f7b0e 100644 --- a/packages/frontend/src/pages/admin/settings.vue +++ b/packages/frontend/src/pages/admin/settings.vue @@ -13,11 +13,6 @@ - - - - - @@ -169,7 +164,6 @@ import MkButton from '@/components/MkButton.vue'; let name: string | null = $ref(null); let description: string | null = $ref(null); -let tosUrl: string | null = $ref(null); let maintainerName: string | null = $ref(null); let maintainerEmail: string | null = $ref(null); let iconUrl: string | null = $ref(null); @@ -194,7 +188,6 @@ async function init() { const meta = await os.api('admin/meta'); name = meta.name; description = meta.description; - tosUrl = meta.tosUrl; iconUrl = meta.iconUrl; bannerUrl = meta.bannerUrl; backgroundImageUrl = meta.backgroundImageUrl; @@ -220,7 +213,6 @@ function save() { os.apiWithDialog('admin/update-meta', { name, description, - tosUrl, iconUrl, bannerUrl, backgroundImageUrl, diff --git a/packages/frontend/src/router.ts b/packages/frontend/src/router.ts index 0769ec2614..fa19682f32 100644 --- a/packages/frontend/src/router.ts +++ b/packages/frontend/src/router.ts @@ -427,6 +427,10 @@ export const routes = [{ path: '/other-settings', name: 'other-settings', component: page(() => import('./pages/admin/other-settings.vue')), + }, { + path: '/server-rules', + name: 'server-rules', + component: page(() => import('./pages/admin/server-rules.vue')), }, { path: '/', component: page(() => import('./pages/_empty_.vue')), diff --git a/packages/frontend/src/store.ts b/packages/frontend/src/store.ts index 710b08d9e0..af1b97d87f 100644 --- a/packages/frontend/src/store.ts +++ b/packages/frontend/src/store.ts @@ -164,7 +164,7 @@ export const defaultStore = markRaw(new Storage('base', { }, animation: { where: 'device', - default: !matchMedia('(prefers-reduced-motion)').matches, + default: !window.matchMedia('(prefers-reduced-motion)').matches, }, animatedMfm: { where: 'device', @@ -188,7 +188,7 @@ export const defaultStore = markRaw(new Storage('base', { }, disableShowingAnimatedImages: { where: 'device', - default: matchMedia('(prefers-reduced-motion)').matches, + default: window.matchMedia('(prefers-reduced-motion)').matches, }, emojiStyle: { where: 'device', diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index 67d12000b8..2fae84c171 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -2348,6 +2348,7 @@ type LiteInstanceMetadata = { imageUrl: string; }[]; translatorAvailable: boolean; + serverRules: string[]; }; // @public (undocumented) diff --git a/packages/misskey-js/src/entities.ts b/packages/misskey-js/src/entities.ts index 0c90e44494..34857f431f 100644 --- a/packages/misskey-js/src/entities.ts +++ b/packages/misskey-js/src/entities.ts @@ -315,6 +315,7 @@ export type LiteInstanceMetadata = { imageUrl: string; }[]; translatorAvailable: boolean; + serverRules: string[]; }; export type DetailedInstanceMetadata = LiteInstanceMetadata & { -- cgit v1.2.3-freya From 67d218fe2bd53ff3d70f15045ebb1110d0b8923e Mon Sep 17 00:00:00 2001 From: syuilo Date: Thu, 20 Apr 2023 09:52:08 +0900 Subject: tweak MkSignupDialog.rules.vue --- cypress/e2e/basic.cy.js | 2 -- packages/frontend/src/components/MkSignupDialog.rules.vue | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'packages/frontend/src/components') diff --git a/cypress/e2e/basic.cy.js b/cypress/e2e/basic.cy.js index b0c3d4c19a..e271894ec1 100644 --- a/cypress/e2e/basic.cy.js +++ b/cypress/e2e/basic.cy.js @@ -53,7 +53,6 @@ describe('After setup instance', () => { cy.get('[data-cy-signup]').click(); cy.get('[data-cy-signup-rules-continue]').should('be.disabled'); - cy.get('[data-cy-signup-rules-notes] [data-cy-folder-header]').click(); cy.get('[data-cy-signup-rules-notes-agree] [data-cy-switch-toggle]').click(); cy.get('[data-cy-signup-rules-continue]').should('not.be.disabled'); cy.get('[data-cy-signup-rules-continue]').click(); @@ -78,7 +77,6 @@ describe('After setup instance', () => { // ユーザー名が重複している場合の挙動確認 cy.get('[data-cy-signup]').click(); cy.get('[data-cy-signup-rules-continue]').should('be.disabled'); - cy.get('[data-cy-signup-rules-notes] [data-cy-folder-header]').click(); cy.get('[data-cy-signup-rules-notes-agree] [data-cy-switch-toggle]').click(); cy.get('[data-cy-signup-rules-continue]').should('not.be.disabled'); cy.get('[data-cy-signup-rules-continue]').click(); diff --git a/packages/frontend/src/components/MkSignupDialog.rules.vue b/packages/frontend/src/components/MkSignupDialog.rules.vue index be1c7f8c35..3b39b72d37 100644 --- a/packages/frontend/src/components/MkSignupDialog.rules.vue +++ b/packages/frontend/src/components/MkSignupDialog.rules.vue @@ -18,7 +18,7 @@ {{ i18n.ts.agree }} - + @@ -27,7 +27,7 @@ {{ i18n.ts.agree }} - + -- cgit v1.2.3-freya From 7cc797062d970ebe298b9f8d73370fca8d218b6d Mon Sep 17 00:00:00 2001 From: syuilo Date: Thu, 20 Apr 2023 10:11:48 +0900 Subject: tweak MkSignupDialog.rules.vue --- locales/ja-JP.yml | 1 + packages/frontend/src/components/MkSignupDialog.rules.vue | 10 ++++++++-- packages/frontend/src/components/MkSignupDialog.vue | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) (limited to 'packages/frontend/src/components') diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index cd9521a9f8..8c1334c6a8 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1013,6 +1013,7 @@ horizontal: "横" position: "位置" serverRules: "サーバールール" pleaseConfirmBelowBeforeSignup: "このサーバーに登録する前に、以下を確認してください。" +pleaseAgreeAllToContinue: "続けるには、全ての「同意する」にチェックが入っている必要があります。" continue: "続ける" _serverRules: diff --git a/packages/frontend/src/components/MkSignupDialog.rules.vue b/packages/frontend/src/components/MkSignupDialog.rules.vue index 3b39b72d37..ed179ffdeb 100644 --- a/packages/frontend/src/components/MkSignupDialog.rules.vue +++ b/packages/frontend/src/components/MkSignupDialog.rules.vue @@ -36,7 +36,12 @@ {{ i18n.ts.agree }} - {{ i18n.ts.continue }} +
{{ i18n.ts.pleaseAgreeAllToContinue }}
+ +
+ {{ i18n.ts.cancel }} + {{ i18n.ts.continue }} +
@@ -62,7 +67,8 @@ const agreed = computed(() => { }); const emit = defineEmits<{ - (ev: 'accept'): void; + (ev: 'cancel'): void; + (ev: 'done'): void; }>(); diff --git a/packages/frontend/src/components/MkSignupDialog.vue b/packages/frontend/src/components/MkSignupDialog.vue index b4fc564d36..17f8b86425 100644 --- a/packages/frontend/src/components/MkSignupDialog.vue +++ b/packages/frontend/src/components/MkSignupDialog.vue @@ -17,7 +17,7 @@ :leave-to-class="$style.transition_x_leaveTo" > + + diff --git a/packages/frontend/src/scripts/get-note-menu.ts b/packages/frontend/src/scripts/get-note-menu.ts index d91f0b0eb6..c8a6100253 100644 --- a/packages/frontend/src/scripts/get-note-menu.ts +++ b/packages/frontend/src/scripts/get-note-menu.ts @@ -211,6 +211,12 @@ export function getNoteMenu(props: { }, {}, 'closed'); } + function showRenotes(): void { + os.popup(defineAsyncComponent(() => import('@/components/MkRenotedUsersDialog.vue')), { + noteId: appearNote.id, + }, {}, 'closed'); + } + async function translate(): Promise { if (props.translation.value != null) return; props.translating.value = true; @@ -241,8 +247,12 @@ export function getNoteMenu(props: { text: i18n.ts.details, action: openDetail, }, { - icon: 'ti ti-users', - text: i18n.ts.reactions, + icon: 'ti ti-repeat', + text: i18n.ts.renotesList, + action: showRenotes, + }, { + icon: 'ti ti-icons', + text: i18n.ts.reactionsList, action: showReactions, }, { icon: 'ti ti-copy', -- cgit v1.2.3-freya From 9d5911d4e436859127f38d5fcdaa6cb5ce6d01e6 Mon Sep 17 00:00:00 2001 From: "Acid Chicken (硫酸鶏)" Date: Sat, 29 Apr 2023 22:57:46 +0900 Subject: feat: make `MkImgWithBlurhash` transitionable (#10500) * feat: make `MkImgWithBlurhash` animatable * refactor: split out transition styles * fix: bug * test: waitFor image loads * style: remove unused await * fix * fix type error --------- Co-authored-by: tamaina --- .../MkGalleryPostPreview.stories.impl.ts | 8 ++-- .../src/components/MkGalleryPostPreview.vue | 52 ++++++++++++++++------ .../frontend/src/components/MkImgWithBlurhash.vue | 52 +++++++++++++++++++--- 3 files changed, 88 insertions(+), 24 deletions(-) (limited to 'packages/frontend/src/components') diff --git a/packages/frontend/src/components/MkGalleryPostPreview.stories.impl.ts b/packages/frontend/src/components/MkGalleryPostPreview.stories.impl.ts index e46a708192..57b3e75513 100644 --- a/packages/frontend/src/components/MkGalleryPostPreview.stories.impl.ts +++ b/packages/frontend/src/components/MkGalleryPostPreview.stories.impl.ts @@ -28,9 +28,11 @@ export const Default = { 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}`); + expect(links).toHaveLength(2); + expect(links[0]).toHaveAttribute('href', `/gallery/${galleryPost().id}`); + expect(links[1]).toHaveAttribute('href', `/@${galleryPost().user.username}@${galleryPost().user.host}`); + const images = canvas.getAllByRole('img'); + await waitFor(() => expect(Promise.all(images.map((image) => image.decode()))).resolves.toBeDefined()); }, args: { post: galleryPost(), diff --git a/packages/frontend/src/components/MkGalleryPostPreview.vue b/packages/frontend/src/components/MkGalleryPostPreview.vue index 944f5ad97b..4f8f7b945a 100644 --- a/packages/frontend/src/components/MkGalleryPostPreview.vue +++ b/packages/frontend/src/components/MkGalleryPostPreview.vue @@ -1,9 +1,21 @@ @@ -52,7 +53,7 @@
{{ i18n.ts.pushNotification }}
{{ i18n.t('_initialAccountSetting.pushNotificationDescription', { name: instance.name ?? host }) }}
- {{ i18n.ts.continue }} + {{ i18n.ts.continue }}
@@ -70,7 +71,7 @@
{{ i18n.t('_initialAccountSetting.haveFun', { name: instance.name ?? host }) }}
- {{ i18n.ts.close }} + {{ i18n.ts.close }} -- cgit v1.2.3-freya From b16d7cc6c4b8d670e35e0b32e1527149e2c575ab Mon Sep 17 00:00:00 2001 From: syuilo Date: Tue, 9 May 2023 08:09:16 +0900 Subject: chore(frontend): より柔軟な文言に変更 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- locales/ja-JP.yml | 1 + packages/frontend/src/components/MkUserSetupDialog.vue | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'packages/frontend/src/components') diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index b886cc7bfd..8bbf9459f5 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1041,6 +1041,7 @@ youFollowing: "フォロー中" _initialAccountSetting: accountCreated: "アカウントの作成が完了しました!" + letsStartAccountSetup: "アカウントの初期設定を行いましょう。" letsFillYourProfile: "まずはあなたのプロフィールを設定しましょう。" profileSetting: "プロフィール設定" theseSettingsCanEditLater: "これらの設定は後から変更できます。" diff --git a/packages/frontend/src/components/MkUserSetupDialog.vue b/packages/frontend/src/components/MkUserSetupDialog.vue index c5e75276f0..096b88c309 100644 --- a/packages/frontend/src/components/MkUserSetupDialog.vue +++ b/packages/frontend/src/components/MkUserSetupDialog.vue @@ -23,7 +23,7 @@
{{ i18n.ts._initialAccountSetting.accountCreated }}
-
{{ i18n.ts._initialAccountSetting.letsFillYourProfile }}
+
{{ i18n.ts._initialAccountSetting.letsStartAccountSetup }}
{{ i18n.ts._initialAccountSetting.profileSetting }}
-- cgit v1.2.3-freya From aa28ddf762f88ca355c62edcbfa54e19a2b93c29 Mon Sep 17 00:00:00 2001 From: syuilo Date: Tue, 9 May 2023 08:33:57 +0900 Subject: fix(frontend): fix e2e --- packages/frontend/src/components/MkUserSetupDialog.Profile.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'packages/frontend/src/components') diff --git a/packages/frontend/src/components/MkUserSetupDialog.Profile.vue b/packages/frontend/src/components/MkUserSetupDialog.Profile.vue index 373e2cf8dc..adb8d43349 100644 --- a/packages/frontend/src/components/MkUserSetupDialog.Profile.vue +++ b/packages/frontend/src/components/MkUserSetupDialog.Profile.vue @@ -12,11 +12,11 @@ - + - + -- cgit v1.2.3-freya