summaryrefslogtreecommitdiff
path: root/packages/frontend/src/components
diff options
context:
space:
mode:
authorAcid Chicken (硫酸鶏) <root@acid-chicken.com>2023-04-01 16:26:08 +0900
committerAcid Chicken (硫酸鶏) <root@acid-chicken.com>2023-04-01 16:26:08 +0900
commit1521bb088cbafb53f8c829a60748d4bc0469a8cd (patch)
tree04719cc96897fb3b3e2b606a3d2b76d1945be517 /packages/frontend/src/components
parentfix: pointer handling (diff)
downloadmisskey-1521bb088cbafb53f8c829a60748d4bc0469a8cd.tar.gz
misskey-1521bb088cbafb53f8c829a60748d4bc0469a8cd.tar.bz2
misskey-1521bb088cbafb53f8c829a60748d4bc0469a8cd.zip
build(#10336): finalize
Diffstat (limited to 'packages/frontend/src/components')
-rw-r--r--packages/frontend/src/components/global/MkA.stories.impl.ts2
-rw-r--r--packages/frontend/src/components/global/MkAd.stories.impl.ts8
-rw-r--r--packages/frontend/src/components/global/MkAvatar.stories.impl.ts5
-rw-r--r--packages/frontend/src/components/global/MkCustomEmoji.stories.impl.ts5
-rw-r--r--packages/frontend/src/components/global/MkEmoji.stories.impl.ts1
-rw-r--r--packages/frontend/src/components/global/MkError.stories.meta.ts2
-rw-r--r--packages/frontend/src/components/global/MkLoading.stories.impl.ts8
-rw-r--r--packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.stories.impl.ts6
-rw-r--r--packages/frontend/src/components/global/MkPageHeader.stories.impl.ts93
-rw-r--r--packages/frontend/src/components/global/MkPageHeader.tabs.stories.impl.ts3
-rw-r--r--packages/frontend/src/components/global/MkPageHeader.tabs.vue18
-rw-r--r--packages/frontend/src/components/global/MkStickyContainer.stories.impl.ts3
-rw-r--r--packages/frontend/src/components/global/MkTime.stories.impl.ts312
-rw-r--r--packages/frontend/src/components/global/MkTime.vue6
-rw-r--r--packages/frontend/src/components/global/MkUrl.stories.impl.ts77
-rw-r--r--packages/frontend/src/components/global/MkUserName.stories.impl.ts57
-rw-r--r--packages/frontend/src/components/global/RouterView.stories.impl.ts3
17 files changed, 580 insertions, 29 deletions
diff --git a/packages/frontend/src/components/global/MkA.stories.impl.ts b/packages/frontend/src/components/global/MkA.stories.impl.ts
index 780aa55376..3afec7f81a 100644
--- a/packages/frontend/src/components/global/MkA.stories.impl.ts
+++ b/packages/frontend/src/components/global/MkA.stories.impl.ts
@@ -2,8 +2,8 @@
import { expect } from '@storybook/jest';
import { userEvent, within } from '@storybook/testing-library';
import { StoryObj } from '@storybook/vue3';
-import { tick } from '@/scripts/test-utils';
import MkA from './MkA.vue';
+import { tick } from '@/scripts/test-utils';
export const Default = {
render(args) {
return {
diff --git a/packages/frontend/src/components/global/MkAd.stories.impl.ts b/packages/frontend/src/components/global/MkAd.stories.impl.ts
index 436744b4f6..68f2995642 100644
--- a/packages/frontend/src/components/global/MkAd.stories.impl.ts
+++ b/packages/frontend/src/components/global/MkAd.stories.impl.ts
@@ -82,7 +82,7 @@ export const Square = {
'https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/about-icon.png?raw=true',
},
},
-};
+} satisfies StoryObj<typeof MkAd>;
export const Horizontal = {
...common,
args: {
@@ -94,7 +94,7 @@ export const Horizontal = {
'https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/fedi.jpg?raw=true',
},
},
-};
+} satisfies StoryObj<typeof MkAd>;
export const HorizontalBig = {
...common,
args: {
@@ -106,7 +106,7 @@ export const HorizontalBig = {
'https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/fedi.jpg?raw=true',
},
},
-};
+} satisfies StoryObj<typeof MkAd>;
export const ZeroRatio = {
...Square,
args: {
@@ -117,4 +117,4 @@ export const ZeroRatio = {
},
__hasReduce: false,
},
-};
+} satisfies StoryObj<typeof MkAd>;
diff --git a/packages/frontend/src/components/global/MkAvatar.stories.impl.ts b/packages/frontend/src/components/global/MkAvatar.stories.impl.ts
index 2e7ba29d12..d83164ac5f 100644
--- a/packages/frontend/src/components/global/MkAvatar.stories.impl.ts
+++ b/packages/frontend/src/components/global/MkAvatar.stories.impl.ts
@@ -1,5 +1,4 @@
/* eslint-disable @typescript-eslint/explicit-function-return-type */
-/* eslint-disable import/no-duplicates */
import { StoryObj } from '@storybook/vue3';
import { userDetailed } from '../../../.storybook/fakes';
import MkAvatar from './MkAvatar.vue';
@@ -44,7 +43,7 @@ export const ProfilePage = {
size: 120,
indicator: true,
},
-};
+} satisfies StoryObj<typeof MkAvatar>;
export const ProfilePageCat = {
...ProfilePage,
args: {
@@ -54,4 +53,4 @@ export const ProfilePageCat = {
isCat: true,
},
},
-};
+} satisfies StoryObj<typeof MkAvatar>;
diff --git a/packages/frontend/src/components/global/MkCustomEmoji.stories.impl.ts b/packages/frontend/src/components/global/MkCustomEmoji.stories.impl.ts
index b31b303e7f..e91fc4e2ee 100644
--- a/packages/frontend/src/components/global/MkCustomEmoji.stories.impl.ts
+++ b/packages/frontend/src/components/global/MkCustomEmoji.stories.impl.ts
@@ -1,5 +1,4 @@
/* eslint-disable @typescript-eslint/explicit-function-return-type */
-/* eslint-disable import/no-duplicates */
import { StoryObj } from '@storybook/vue3';
import MkCustomEmoji from './MkCustomEmoji.vue';
export const Default = {
@@ -37,10 +36,10 @@ export const Normal = {
...Default.args,
normal: true,
},
-};
+} satisfies StoryObj<typeof MkCustomEmoji>;
export const Missing = {
...Default,
args: {
name: Default.args.name,
},
-};
+} satisfies StoryObj<typeof MkCustomEmoji>;
diff --git a/packages/frontend/src/components/global/MkEmoji.stories.impl.ts b/packages/frontend/src/components/global/MkEmoji.stories.impl.ts
index 53adf646ff..5baa5c2c84 100644
--- a/packages/frontend/src/components/global/MkEmoji.stories.impl.ts
+++ b/packages/frontend/src/components/global/MkEmoji.stories.impl.ts
@@ -1,5 +1,4 @@
/* eslint-disable @typescript-eslint/explicit-function-return-type */
-/* eslint-disable import/no-duplicates */
import { StoryObj } from '@storybook/vue3';
import MkEmoji from './MkEmoji.vue';
export const Default = {
diff --git a/packages/frontend/src/components/global/MkError.stories.meta.ts b/packages/frontend/src/components/global/MkError.stories.meta.ts
index 7c94421963..51d763ada7 100644
--- a/packages/frontend/src/components/global/MkError.stories.meta.ts
+++ b/packages/frontend/src/components/global/MkError.stories.meta.ts
@@ -2,4 +2,4 @@ export const argTypes = {
retry: {
action: 'retry',
},
-}
+};
diff --git a/packages/frontend/src/components/global/MkLoading.stories.impl.ts b/packages/frontend/src/components/global/MkLoading.stories.impl.ts
index d1e1f33f0e..dd22f92451 100644
--- a/packages/frontend/src/components/global/MkLoading.stories.impl.ts
+++ b/packages/frontend/src/components/global/MkLoading.stories.impl.ts
@@ -34,25 +34,25 @@ export const Inline = {
...Default.args,
inline: true,
},
-};
+} satisfies StoryObj<typeof MkLoading>;
export const Colored = {
...Default,
args: {
...Default.args,
colored: true,
},
-};
+} satisfies StoryObj<typeof MkLoading>;
export const Mini = {
...Default,
args: {
...Default.args,
mini: true,
},
-};
+} satisfies StoryObj<typeof MkLoading>;
export const Em = {
...Default,
args: {
...Default.args,
em: true,
},
-};
+} satisfies StoryObj<typeof MkLoading>;
diff --git a/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.stories.impl.ts b/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.stories.impl.ts
index 720aaa1770..2464061694 100644
--- a/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.stories.impl.ts
+++ b/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.stories.impl.ts
@@ -57,18 +57,18 @@ export const Plain = {
...Default.args,
plain: true,
},
-};
+} satisfies StoryObj<typeof MkMisskeyFlavoredMarkdown>;
export const Nowrap = {
...Default,
args: {
...Default.args,
nowrap: true,
},
-};
+} satisfies StoryObj<typeof MkMisskeyFlavoredMarkdown>;
export const IsNotNote = {
...Default,
args: {
...Default.args,
isNote: false,
},
-};
+} satisfies StoryObj<typeof MkMisskeyFlavoredMarkdown>;
diff --git a/packages/frontend/src/components/global/MkPageHeader.stories.impl.ts b/packages/frontend/src/components/global/MkPageHeader.stories.impl.ts
new file mode 100644
index 0000000000..2a37ef1a88
--- /dev/null
+++ b/packages/frontend/src/components/global/MkPageHeader.stories.impl.ts
@@ -0,0 +1,93 @@
+/* eslint-disable @typescript-eslint/explicit-function-return-type */
+import { StoryObj } from '@storybook/vue3';
+import MkPageHeader from './MkPageHeader.vue';
+export const Empty = {
+ render(args) {
+ return {
+ components: {
+ MkPageHeader,
+ },
+ setup() {
+ return {
+ args,
+ };
+ },
+ computed: {
+ props() {
+ return {
+ ...args,
+ };
+ },
+ },
+ template: '<MkPageHeader v-bind="props" />',
+ };
+ },
+ args: {
+ tabs: [],
+ },
+ parameters: {
+ layout: 'centered',
+ },
+} satisfies StoryObj<typeof MkPageHeader>;
+export const OneTab = {
+ ...Empty,
+ args: {
+ ...Empty.args,
+ tab: 'sometabkey',
+ tabs: [
+ {
+ key: 'sometabkey',
+ title: 'Some Tab Title',
+ },
+ ],
+ },
+} satisfies StoryObj<typeof MkPageHeader>;
+export const Icon = {
+ ...OneTab,
+ args: {
+ ...OneTab.args,
+ tabs: [
+ {
+ ...OneTab.args.tabs[0],
+ icon: 'ti ti-home',
+ },
+ ],
+ },
+} satisfies StoryObj<typeof MkPageHeader>;
+export const IconOnly = {
+ ...Icon,
+ args: {
+ ...Icon.args,
+ tabs: [
+ {
+ ...Icon.args.tabs[0],
+ title: undefined,
+ iconOnly: true,
+ },
+ ],
+ },
+} satisfies StoryObj<typeof MkPageHeader>;
+export const SomeTabs = {
+ ...Empty,
+ args: {
+ ...Empty.args,
+ tab: 'princess',
+ tabs: [
+ {
+ key: 'princess',
+ title: 'Princess',
+ icon: 'ti ti-crown',
+ },
+ {
+ key: 'fairy',
+ title: 'Fairy',
+ icon: 'ti ti-snowflake',
+ },
+ {
+ key: 'angel',
+ title: 'Angel',
+ icon: 'ti ti-feather',
+ },
+ ],
+ },
+} satisfies StoryObj<typeof MkPageHeader>;
diff --git a/packages/frontend/src/components/global/MkPageHeader.tabs.stories.impl.ts b/packages/frontend/src/components/global/MkPageHeader.tabs.stories.impl.ts
new file mode 100644
index 0000000000..6d4460d593
--- /dev/null
+++ b/packages/frontend/src/components/global/MkPageHeader.tabs.stories.impl.ts
@@ -0,0 +1,3 @@
+/* eslint-disable @typescript-eslint/explicit-function-return-type */
+import MkPageHeader_tabs from './MkPageHeader.tabs.vue';
+void MkPageHeader_tabs;
diff --git a/packages/frontend/src/components/global/MkPageHeader.tabs.vue b/packages/frontend/src/components/global/MkPageHeader.tabs.vue
index 42760da08f..9e1da64e61 100644
--- a/packages/frontend/src/components/global/MkPageHeader.tabs.vue
+++ b/packages/frontend/src/components/global/MkPageHeader.tabs.vue
@@ -33,14 +33,18 @@
<script lang="ts">
export type Tab = {
key: string;
- title: string;
- icon?: string;
- iconOnly?: boolean;
onClick?: (ev: MouseEvent) => void;
-} & {
- iconOnly: true;
- iccn: string;
-};
+} & (
+ | {
+ iconOnly?: false;
+ title: string;
+ icon?: string;
+ }
+ | {
+ iconOnly: true;
+ icon: string;
+ }
+);
</script>
<script lang="ts" setup>
diff --git a/packages/frontend/src/components/global/MkStickyContainer.stories.impl.ts b/packages/frontend/src/components/global/MkStickyContainer.stories.impl.ts
new file mode 100644
index 0000000000..97b8cc0c5b
--- /dev/null
+++ b/packages/frontend/src/components/global/MkStickyContainer.stories.impl.ts
@@ -0,0 +1,3 @@
+/* eslint-disable @typescript-eslint/explicit-function-return-type */
+import MkStickyContainer from './MkStickyContainer.vue';
+void MkStickyContainer;
diff --git a/packages/frontend/src/components/global/MkTime.stories.impl.ts b/packages/frontend/src/components/global/MkTime.stories.impl.ts
new file mode 100644
index 0000000000..fd8e874dc3
--- /dev/null
+++ b/packages/frontend/src/components/global/MkTime.stories.impl.ts
@@ -0,0 +1,312 @@
+/* eslint-disable @typescript-eslint/explicit-function-return-type */
+import { expect } from '@storybook/jest';
+import { StoryObj } from '@storybook/vue3';
+import MkTime from './MkTime.vue';
+import { i18n } from '@/i18n';
+import { dateTimeFormat } from '@/scripts/intl-const';
+const now = new Date('2023-04-01T00:00:00.000Z');
+const future = new Date(8640000000000000);
+const oneHourAgo = new Date(now.getTime() - 3600000);
+const oneDayAgo = new Date(now.getTime() - 86400000);
+const oneWeekAgo = new Date(now.getTime() - 604800000);
+const oneMonthAgo = new Date(now.getTime() - 2592000000);
+const oneYearAgo = new Date(now.getTime() - 31536000000);
+export const Empty = {
+ render(args) {
+ return {
+ components: {
+ MkTime,
+ },
+ setup() {
+ return {
+ args,
+ };
+ },
+ computed: {
+ props() {
+ return {
+ ...args,
+ };
+ },
+ },
+ template: '<MkTime v-bind="props" />',
+ };
+ },
+ async play({ canvasElement }) {
+ await expect(canvasElement).toHaveTextContent(i18n.ts._ago.invalid);
+ },
+ args: {
+ },
+ parameters: {
+ layout: 'centered',
+ },
+} satisfies StoryObj<typeof MkTime>;
+export const RelativeFuture = {
+ ...Empty,
+ async play({ canvasElement }) {
+ await expect(canvasElement).toHaveTextContent(i18n.ts._ago.future);
+ },
+ args: {
+ ...Empty.args,
+ time: future,
+ },
+} satisfies StoryObj<typeof MkTime>;
+export const AbsoluteFuture = {
+ ...Empty,
+ async play({ canvasElement, args }) {
+ await expect(canvasElement).toHaveTextContent(dateTimeFormat.format(args.time));
+ },
+ args: {
+ ...Empty.args,
+ time: future,
+ mode: 'absolute',
+ },
+} satisfies StoryObj<typeof MkTime>;
+export const DetailFuture = {
+ ...Empty,
+ async play(context) {
+ await AbsoluteFuture.play(context);
+ await expect(context.canvasElement).toHaveTextContent(' (');
+ await RelativeFuture.play(context);
+ await expect(context.canvasElement).toHaveTextContent(')');
+ },
+ args: {
+ ...Empty.args,
+ time: future,
+ mode: 'detail',
+ },
+} satisfies StoryObj<typeof MkTime>;
+export const RelativeNow = {
+ ...Empty,
+ async play({ canvasElement }) {
+ await expect(canvasElement).toHaveTextContent(i18n.ts._ago.justNow);
+ },
+ args: {
+ ...Empty.args,
+ time: now,
+ origin: now,
+ mode: 'relative',
+ },
+} satisfies StoryObj<typeof MkTime>;
+export const AbsoluteNow = {
+ ...Empty,
+ async play({ canvasElement, args }) {
+ await expect(canvasElement).toHaveTextContent(dateTimeFormat.format(args.time));
+ },
+ args: {
+ ...Empty.args,
+ time: now,
+ origin: now,
+ mode: 'absolute',
+ },
+} satisfies StoryObj<typeof MkTime>;
+export const DetailNow = {
+ ...Empty,
+ async play(context) {
+ await AbsoluteNow.play(context);
+ await expect(context.canvasElement).toHaveTextContent(' (');
+ await RelativeNow.play(context);
+ await expect(context.canvasElement).toHaveTextContent(')');
+ },
+ args: {
+ ...Empty.args,
+ time: now,
+ origin: now,
+ mode: 'detail',
+ },
+} satisfies StoryObj<typeof MkTime>;
+export const RelativeOneHourAgo = {
+ ...Empty,
+ async play({ canvasElement }) {
+ await expect(canvasElement).toHaveTextContent(i18n.t('_ago.hoursAgo', { n: 1 }));
+ },
+ args: {
+ ...Empty.args,
+ time: oneHourAgo,
+ origin: now,
+ mode: 'relative',
+ },
+} satisfies StoryObj<typeof MkTime>;
+export const AbsoluteOneHourAgo = {
+ ...Empty,
+ async play({ canvasElement, args }) {
+ await expect(canvasElement).toHaveTextContent(dateTimeFormat.format(args.time));
+ },
+ args: {
+ ...Empty.args,
+ time: oneHourAgo,
+ origin: now,
+ mode: 'absolute',
+ },
+} satisfies StoryObj<typeof MkTime>;
+export const DetailOneHourAgo = {
+ ...Empty,
+ async play(context) {
+ await AbsoluteOneHourAgo.play(context);
+ await expect(context.canvasElement).toHaveTextContent(' (');
+ await RelativeOneHourAgo.play(context);
+ await expect(context.canvasElement).toHaveTextContent(')');
+ },
+ args: {
+ ...Empty.args,
+ time: oneHourAgo,
+ origin: now,
+ mode: 'detail',
+ },
+} satisfies StoryObj<typeof MkTime>;
+export const RelativeOneDayAgo = {
+ ...Empty,
+ async play({ canvasElement }) {
+ await expect(canvasElement).toHaveTextContent(i18n.t('_ago.daysAgo', { n: 1 }));
+ },
+ args: {
+ ...Empty.args,
+ time: oneDayAgo,
+ origin: now,
+ mode: 'relative',
+ },
+} satisfies StoryObj<typeof MkTime>;
+export const AbsoluteOneDayAgo = {
+ ...Empty,
+ async play({ canvasElement, args }) {
+ await expect(canvasElement).toHaveTextContent(dateTimeFormat.format(args.time));
+ },
+ args: {
+ ...Empty.args,
+ time: oneDayAgo,
+ origin: now,
+ mode: 'absolute',
+ },
+} satisfies StoryObj<typeof MkTime>;
+export const DetailOneDayAgo = {
+ ...Empty,
+ async play(context) {
+ await AbsoluteOneDayAgo.play(context);
+ await expect(context.canvasElement).toHaveTextContent(' (');
+ await RelativeOneDayAgo.play(context);
+ await expect(context.canvasElement).toHaveTextContent(')');
+ },
+ args: {
+ ...Empty.args,
+ time: oneDayAgo,
+ origin: now,
+ mode: 'detail',
+ },
+} satisfies StoryObj<typeof MkTime>;
+export const RelativeOneWeekAgo = {
+ ...Empty,
+ async play({ canvasElement }) {
+ await expect(canvasElement).toHaveTextContent(i18n.t('_ago.weeksAgo', { n: 1 }));
+ },
+ args: {
+ ...Empty.args,
+ time: oneWeekAgo,
+ origin: now,
+ mode: 'relative',
+ },
+} satisfies StoryObj<typeof MkTime>;
+export const AbsoluteOneWeekAgo = {
+ ...Empty,
+ async play({ canvasElement, args }) {
+ await expect(canvasElement).toHaveTextContent(dateTimeFormat.format(args.time));
+ },
+ args: {
+ ...Empty.args,
+ time: oneWeekAgo,
+ origin: now,
+ mode: 'absolute',
+ },
+} satisfies StoryObj<typeof MkTime>;
+export const DetailOneWeekAgo = {
+ ...Empty,
+ async play(context) {
+ await AbsoluteOneWeekAgo.play(context);
+ await expect(context.canvasElement).toHaveTextContent(' (');
+ await RelativeOneWeekAgo.play(context);
+ await expect(context.canvasElement).toHaveTextContent(')');
+ },
+ args: {
+ ...Empty.args,
+ time: oneWeekAgo,
+ origin: now,
+ mode: 'detail',
+ },
+} satisfies StoryObj<typeof MkTime>;
+export const RelativeOneMonthAgo = {
+ ...Empty,
+ async play({ canvasElement }) {
+ await expect(canvasElement).toHaveTextContent(i18n.t('_ago.monthsAgo', { n: 1 }));
+ },
+ args: {
+ ...Empty.args,
+ time: oneMonthAgo,
+ origin: now,
+ mode: 'relative',
+ },
+} satisfies StoryObj<typeof MkTime>;
+export const AbsoluteOneMonthAgo = {
+ ...Empty,
+ async play({ canvasElement, args }) {
+ await expect(canvasElement).toHaveTextContent(dateTimeFormat.format(args.time));
+ },
+ args: {
+ ...Empty.args,
+ time: oneMonthAgo,
+ origin: now,
+ mode: 'absolute',
+ },
+} satisfies StoryObj<typeof MkTime>;
+export const DetailOneMonthAgo = {
+ ...Empty,
+ async play(context) {
+ await AbsoluteOneMonthAgo.play(context);
+ await expect(context.canvasElement).toHaveTextContent(' (');
+ await RelativeOneMonthAgo.play(context);
+ await expect(context.canvasElement).toHaveTextContent(')');
+ },
+ args: {
+ ...Empty.args,
+ time: oneMonthAgo,
+ origin: now,
+ mode: 'detail',
+ },
+} satisfies StoryObj<typeof MkTime>;
+export const RelativeOneYearAgo = {
+ ...Empty,
+ async play({ canvasElement }) {
+ await expect(canvasElement).toHaveTextContent(i18n.t('_ago.yearsAgo', { n: 1 }));
+ },
+ args: {
+ ...Empty.args,
+ time: oneYearAgo,
+ origin: now,
+ mode: 'relative',
+ },
+} satisfies StoryObj<typeof MkTime>;
+export const AbsoluteOneYearAgo = {
+ ...Empty,
+ async play({ canvasElement, args }) {
+ await expect(canvasElement).toHaveTextContent(dateTimeFormat.format(args.time));
+ },
+ args: {
+ ...Empty.args,
+ time: oneYearAgo,
+ origin: now,
+ mode: 'absolute',
+ },
+} satisfies StoryObj<typeof MkTime>;
+export const DetailOneYearAgo = {
+ ...Empty,
+ async play(context) {
+ await AbsoluteOneYearAgo.play(context);
+ await expect(context.canvasElement).toHaveTextContent(' (');
+ await RelativeOneYearAgo.play(context);
+ await expect(context.canvasElement).toHaveTextContent(')');
+ },
+ args: {
+ ...Empty.args,
+ time: oneYearAgo,
+ origin: now,
+ mode: 'detail',
+ },
+} satisfies StoryObj<typeof MkTime>;
diff --git a/packages/frontend/src/components/global/MkTime.vue b/packages/frontend/src/components/global/MkTime.vue
index 3fa8bb9adc..99169512db 100644
--- a/packages/frontend/src/components/global/MkTime.vue
+++ b/packages/frontend/src/components/global/MkTime.vue
@@ -14,8 +14,10 @@ import { dateTimeFormat } from '@/scripts/intl-const';
const props = withDefaults(defineProps<{
time: Date | string | number | null;
+ origin?: Date | null;
mode?: 'relative' | 'absolute' | 'detail';
}>(), {
+ origin: null,
mode: 'relative',
});
@@ -25,7 +27,7 @@ const _time = props.time == null ? NaN :
const invalid = Number.isNaN(_time);
const absolute = !invalid ? dateTimeFormat.format(_time) : i18n.ts._ago.invalid;
-let now = $ref((new Date()).getTime());
+let now = $ref((props.origin ?? new Date()).getTime());
const relative = $computed<string>(() => {
if (props.mode === 'absolute') return ''; // absoluteではrelativeを使わないので計算しない
if (invalid) return i18n.ts._ago.invalid;
@@ -46,7 +48,7 @@ const relative = $computed<string>(() => {
let tickId: number;
function tick() {
- now = (new Date()).getTime();
+ now = props.origin ?? (new Date()).getTime();
const ago = (now - _time) / 1000/*ms*/;
const next = ago < 60 ? 10000 : ago < 3600 ? 60000 : 180000;
diff --git a/packages/frontend/src/components/global/MkUrl.stories.impl.ts b/packages/frontend/src/components/global/MkUrl.stories.impl.ts
new file mode 100644
index 0000000000..06de1d3e90
--- /dev/null
+++ b/packages/frontend/src/components/global/MkUrl.stories.impl.ts
@@ -0,0 +1,77 @@
+/* eslint-disable @typescript-eslint/explicit-function-return-type */
+import { expect } from '@storybook/jest';
+import { userEvent, within } from '@storybook/testing-library';
+import { StoryObj } from '@storybook/vue3';
+import { rest } from 'msw';
+import { commonHandlers } from '../../../.storybook/mocks';
+import MkUrl from './MkUrl.vue';
+export const Default = {
+ render(args) {
+ return {
+ components: {
+ MkUrl,
+ },
+ setup() {
+ return {
+ args,
+ };
+ },
+ computed: {
+ props() {
+ return {
+ ...args,
+ };
+ },
+ },
+ template: '<MkUrl v-bind="props">Text</MkUrl>',
+ };
+ },
+ async play({ canvasElement }) {
+ const canvas = within(canvasElement);
+ const a = canvas.getByRole<HTMLAnchorElement>('link');
+ await expect(a).toHaveAttribute('href', 'https://misskey-hub.net/');
+ await userEvent.hover(a);
+ /*
+ await tick(); // FIXME: wait for network request
+ const anchors = canvas.getAllByRole<HTMLAnchorElement>('link');
+ const popup = anchors.find(anchor => anchor !== a)!; // eslint-disable-line @typescript-eslint/no-non-null-assertion
+ await expect(popup).toBeInTheDocument();
+ await expect(popup).toHaveAttribute('href', 'https://misskey-hub.net/');
+ await expect(popup).toHaveTextContent('Misskey Hub');
+ await expect(popup).toHaveTextContent('Misskeyはオープンソースの分散型ソーシャルネットワーキングプラットフォームです。');
+ await expect(popup).toHaveTextContent('misskey-hub.net');
+ const icon = within(popup).getByRole('img');
+ await expect(icon).toBeInTheDocument();
+ await expect(icon).toHaveAttribute('src', 'https://misskey-hub.net/favicon.ico');
+ */
+ await userEvent.unhover(a);
+ },
+ args: {
+ url: 'https://misskey-hub.net/',
+ },
+ parameters: {
+ layout: 'centered',
+ msw: {
+ handlers: [
+ ...commonHandlers,
+ rest.get('/url', (req, res, ctx) => {
+ return res(ctx.json({
+ title: 'Misskey Hub',
+ icon: 'https://misskey-hub.net/favicon.ico',
+ description: 'Misskeyはオープンソースの分散型ソーシャルネットワーキングプラットフォームです。',
+ thumbnail: null,
+ player: {
+ url: null,
+ width: null,
+ height: null,
+ allow: [],
+ },
+ sitename: 'misskey-hub.net',
+ sensitive: false,
+ url: 'https://misskey-hub.net/',
+ }));
+ }),
+ ],
+ },
+ },
+} satisfies StoryObj<typeof MkUrl>;
diff --git a/packages/frontend/src/components/global/MkUserName.stories.impl.ts b/packages/frontend/src/components/global/MkUserName.stories.impl.ts
new file mode 100644
index 0000000000..37d895d042
--- /dev/null
+++ b/packages/frontend/src/components/global/MkUserName.stories.impl.ts
@@ -0,0 +1,57 @@
+/* eslint-disable @typescript-eslint/explicit-function-return-type */
+import { expect } from '@storybook/jest';
+import { userEvent, within } from '@storybook/testing-library';
+import { StoryObj } from '@storybook/vue3';
+import { userDetailed } from '../../../.storybook/fakes';
+import MkUserName from './MkUserName.vue';
+export const Default = {
+ render(args) {
+ return {
+ components: {
+ MkUserName,
+ },
+ setup() {
+ return {
+ args,
+ };
+ },
+ computed: {
+ props() {
+ return {
+ ...args,
+ };
+ },
+ },
+ template: '<MkUserName v-bind="props"/>',
+ };
+ },
+ async play({ canvasElement }) {
+ await expect(canvasElement).toHaveTextContent(userDetailed.name);
+ },
+ args: {
+ user: userDetailed,
+ },
+ parameters: {
+ layout: 'centered',
+ },
+} satisfies StoryObj<typeof MkUserName>;
+export const Anonymous = {
+ ...Default,
+ async play({ canvasElement }) {
+ await expect(canvasElement).toHaveTextContent(userDetailed.username);
+ },
+ args: {
+ ...Default.args,
+ user: {
+ ...userDetailed,
+ name: null,
+ },
+ },
+} satisfies StoryObj<typeof MkUserName>;
+export const Wrap = {
+ ...Default,
+ args: {
+ ...Default.args,
+ nowrap: false,
+ },
+} satisfies StoryObj<typeof MkUserName>;
diff --git a/packages/frontend/src/components/global/RouterView.stories.impl.ts b/packages/frontend/src/components/global/RouterView.stories.impl.ts
new file mode 100644
index 0000000000..7910b8b3cb
--- /dev/null
+++ b/packages/frontend/src/components/global/RouterView.stories.impl.ts
@@ -0,0 +1,3 @@
+/* eslint-disable @typescript-eslint/explicit-function-return-type */
+import RouterView from './RouterView.vue';
+void RouterView;