Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .storybook/preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { Decorator, Preview } from '@storybook/nextjs-vite';
import { useEffect, useRef, type ReactNode } from 'react';
import { ThemeProvider, useTheme } from 'next-themes';
import { useGlobals } from 'storybook/preview-api';
import { INITIAL_VIEWPORTS } from 'storybook/viewport';
import 'slick-carousel/slick/slick.css';
import 'slick-carousel/slick/slick-theme.css';
import '@/styles/globals.css';
Expand Down Expand Up @@ -87,6 +88,9 @@ const preview: Preview = {
},
parameters: {
layout: 'fullscreen',
viewport: {
options: INITIAL_VIEWPORTS,
},
nextjs: {
appDirectory: true,
navigation: {
Expand Down
2 changes: 1 addition & 1 deletion src/components/Common/BreadCrumb/index.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,5 @@ export const LongTitle: Story = {
},
},
},
globals: { viewport: { value: 'mobile1', isRotated: false } },
globals: { viewport: { value: 'iphone13promax', isRotated: false } },
};
12 changes: 12 additions & 0 deletions src/components/Common/CodeBlock/index.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { Meta, StoryObj } from '@storybook/nextjs-vite';
import { expect } from 'storybook/test';
import CodeBlock, { codeBlockStyles } from '.';

const sampleCode = `export function greeting(name: string) {
Expand All @@ -20,6 +21,17 @@ export const Default: Story = {
},
};

export const WithFilename: Story = {
args: {
filename: 'greeting.ts',
children: <code className={codeBlockStyles.code}>{sampleCode}</code>,
},
play: async ({ canvas }) => {
await expect(canvas.getByText('greeting.ts')).toBeVisible();
await expect(canvas.getByRole('region', { name: 'コードブロック: greeting.ts' })).toBeVisible();
},
};

export const LongLine: Story = {
args: {
children: (
Expand Down
9 changes: 6 additions & 3 deletions src/components/Common/CodeBlock/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import styles from './index.module.css';

/* eslint-disable jsx-a11y/no-noninteractive-tabindex -- Scrollable code regions need keyboard focus. */

type Props = ComponentPropsWithoutRef<'pre'>;
type Props = ComponentPropsWithoutRef<'pre'> & {
filename?: string;
};

export const getReactNodeText = (node: ReactNode): string => {
if (typeof node === 'string' || typeof node === 'number') {
Expand All @@ -24,19 +26,20 @@ export const getReactNodeText = (node: ReactNode): string => {
return '';
};

export default function CodeBlock({ children, className, ...props }: Props) {
export default function CodeBlock({ children, className, filename, ...props }: Props) {
const [wrapped, setWrapped] = useState(false);
const wrapClassName = wrapped ? styles.wrapped : styles.unwrapped;

return (
<div className={styles.codeBlockFrame}>
<CodeBlockToolbar
filename={filename}
getCodeText={() => getReactNodeText(children)}
wrapped={wrapped}
onWrappedChange={setWrapped}
/>
<pre
aria-label="コードブロック"
aria-label={filename ? `コードブロック: ${filename}` : 'コードブロック'}
role="region"
tabIndex={0}
className={`${styles.codeBlock} ${wrapClassName} ${className ?? ''}`.trim()}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@

.content > table th {
background-color: var(--color-bg-sub);
color: var(--color-theme-light-text);
text-align: left;
padding: 1rem;
}
Expand Down
2 changes: 1 addition & 1 deletion src/components/Common/Layouts/Header/index.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const Desktop: Story = {
};

export const Mobile: Story = {
globals: { viewport: { value: 'mobile1', isRotated: false } },
globals: { viewport: { value: 'iphone13promax', isRotated: false } },
play: async ({ canvas }) => {
await expect(canvas.getByRole('button', { name: 'メニューを開く' })).toBeVisible();
},
Expand Down
15 changes: 1 addition & 14 deletions src/components/Common/Layouts/ThemeSwitch/index.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { Meta, StoryObj } from '@storybook/nextjs-vite';
import { expect, userEvent } from 'storybook/test';
import ThemeSwitch from '.';

const meta = {
Expand All @@ -11,16 +10,4 @@ const meta = {
export default meta;
type Story = StoryObj<typeof meta>;

export const Default: Story = {
play: async ({ canvas }) => {
const switchToDarkButton = await canvas.findByRole('button', {
name: 'ダークテーマに切り替え',
});

await userEvent.click(switchToDarkButton);

await expect(
canvas.getByRole('button', { name: 'ライトテーマに切り替え' }),
).toBeInTheDocument();
},
};
export const Default: Story = {};
6 changes: 2 additions & 4 deletions src/components/Common/Markdown/index.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,11 @@ const content = `## 固定ページの見出し

本文には[内部リンク](/profile)と[外部リンク](https://example.com)を含められます。

### リストと引用
### リスト

- ひとつ目の項目
- ふたつ目の項目

> 引用文の表示例です。

### コード

~~~ts
Expand All @@ -30,5 +28,5 @@ export default meta;
type Story = StoryObj<typeof meta>;

export const FixedPageContent: Story = {
args: { content, headingIds: ['page-heading', 'list-and-quote', 'code'] },
args: { content, headingIds: ['page-heading', 'list', 'code'] },
};
13 changes: 11 additions & 2 deletions src/components/Common/TableOfContent/index.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,16 @@ type Story = StoryObj<typeof meta>;

export const Default: Story = { args: { headings } };

export const Sidebar: Story = { args: { headings, sidebar: true } };
export const Sidebar: Story = {
args: { headings, sidebar: true },
decorators: [
(Story) => (
<div className="w-full max-w-sm">
<Story />
</div>
),
],
};

export const DeepHierarchy: Story = {
args: {
Expand All @@ -30,5 +39,5 @@ export const DeepHierarchy: Story = {
{ id: 'verification', title: '動作確認で確認しておきたい長い見出し', level: 2 },
],
},
globals: { viewport: { value: 'mobile1', isRotated: false } },
globals: { viewport: { value: 'iphone13promax', isRotated: false } },
};
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,11 @@
outline-offset: var(--focus-ring-offset);
}

.content iframe[data-focus-visible='true'] {
outline: var(--focus-ring-width) solid var(--color-focus-ring) !important;
outline-offset: var(--focus-ring-offset);
}

.content > figure {
margin: 2rem 0;
}
Expand Down Expand Up @@ -155,6 +160,7 @@

.content > table th {
background-color: var(--color-bg-sub);
color: var(--color-theme-light-text);
text-align: left;
padding: 1rem;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,27 @@ function CustomHtml({ html, sponsorUrl }: Props) {

const cleanupMoshimoEasyLinkFallback = setupMoshimoEasyLinkFallback(content);

let iframeFocusFrame: number | undefined;
const clearIframeFocus = () => {
content.querySelectorAll('iframe[data-focus-visible]').forEach((iframe) => {
iframe.removeAttribute('data-focus-visible');
});
};
const syncIframeFocus = () => {
window.cancelAnimationFrame(iframeFocusFrame ?? 0);
iframeFocusFrame = window.requestAnimationFrame(() => {
clearIframeFocus();
const activeElement = document.activeElement;

if (activeElement instanceof HTMLIFrameElement && content.contains(activeElement)) {
activeElement.dataset.focusVisible = 'true';
}
});
};

window.addEventListener('blur', syncIframeFocus);
window.addEventListener('focus', clearIframeFocus);

const observer = new MutationObserver(() => {
syncCustomHtmlEnhancements();
});
Expand All @@ -61,6 +82,10 @@ function CustomHtml({ html, sponsorUrl }: Props) {

return () => {
cleanupMoshimoEasyLinkFallback();
window.cancelAnimationFrame(iframeFocusFrame ?? 0);
window.removeEventListener('blur', syncIframeFocus);
window.removeEventListener('focus', clearIframeFocus);
clearIframeFocus();
observer.disconnect();
window.clearTimeout(timer);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ type Story = StoryObj<typeof meta>;

export const MultipleImages: Story = {};
export const SingleImage: Story = { args: { block: { image_slider: [images[0]] } } };
export const Mobile: Story = { globals: { viewport: { value: 'mobile1', isRotated: false } } };
export const Mobile: Story = {
globals: { viewport: { value: 'iphone13promax', isRotated: false } },
};
export const NextImageInteraction: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@

.content > table th {
background-color: var(--color-bg-sub);
color: var(--color-theme-light-text);
text-align: left;
padding: 1rem;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const tableHtml = `
`;

const articleHtml = `
<p>本文には<strong>強調</strong><a href="https://example.com">リンク</a>が含まれます。</p>
<p>本文には<strong>強調</strong>、<span class="underline_blue">青マーカー</span>、<span class="underline_red">赤マーカー</span>、<span class="underline_yellow">黄マーカー</span>、<span class="underline_code">inlineCode()</span>、<a href="https://example.com">リンク</a>が含まれます。</p>
<h2>見出し2</h2>
<p>段落の余白と行間を確認するための文章です。</p>
<h3>見出し3</h3>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,5 @@ export const LongText: Story = {
'文章が長い場合でも、画像と吹き出しの位置関係を保ちながら自然に折り返されることを確認します。スマートフォンの画面幅でも内容がはみ出さないことが重要です。',
},
},
globals: { viewport: { value: 'mobile1', isRotated: false } },
globals: { viewport: { value: 'iphone13promax', isRotated: false } },
};
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export default function SpeechBubble({ block }: Props) {
<img
src={formatMicroCmsImageUrl(block.bubble_image.url, {
width: 150,
height: 150,
quality: 70,
fit: 'crop',
})}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@

.tab_merit_box ul {
list-style: disc;
margin-left: 50px;
margin-left: 0;
padding-left: 1.25rem;
}

.tab_merit_box_icon {
Expand All @@ -28,7 +29,8 @@

.tab_demerit_box ul {
list-style: disc;
margin-left: 50px;
margin-left: 0;
padding-left: 1.25rem;
}

.tab_demerit_box_icon {
Expand All @@ -47,7 +49,8 @@

.tab_point_box ul {
list-style: disc;
margin-left: 50px;
margin-left: 0;
padding-left: 1.25rem;
}

.tab_point_box_icon {
Expand All @@ -66,7 +69,8 @@

.tab_common_box ul {
list-style: disc;
margin-left: 50px;
margin-left: 0;
padding-left: 1.25rem;
}

.tab_common_box_icon {
Expand All @@ -86,7 +90,8 @@

.tab_merit_box ul {
list-style: disc;
margin-left: 25px;
margin-left: 0;
padding-left: 1.25rem;
}

.tab_merit_box_icon {
Expand All @@ -105,7 +110,8 @@

.tab_demerit_box ul {
list-style: disc;
margin-left: 25px;
margin-left: 0;
padding-left: 1.25rem;
}

.tab_demerit_box_icon {
Expand All @@ -124,7 +130,8 @@

.tab_point_box ul {
list-style: disc;
margin-left: 25px;
margin-left: 0;
padding-left: 1.25rem;
}

.tab_point_box_icon {
Expand All @@ -143,7 +150,8 @@

.tab_common_box ul {
list-style: disc;
margin-left: 25px;
margin-left: 0;
padding-left: 1.25rem;
}

.tab_common_box_icon {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,13 @@ export const Merit: Story = { args: { merit: true } };
export const Demerit: Story = { args: { demerit: true } };
export const Point: Story = { args: { point: true } };
export const Common: Story = { args: { common: true } };
export const CommonList: Story = {
args: {
block: {
...block,
box_common:
'<ul><li>対象となる利用環境を確認する</li><li>必要な設定を済ませる</li><li>表示と動作を確認する</li></ul>',
},
common: true,
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export default function TabBox({
return (
<>
<div
className={`${merit && styles.tab_merit_box} ${demerit && styles.tab_demerit_box} ${point && styles.tab_point_box} ${common && styles.tab_common_box} text-gray-700 flex items-center`}
className={`${merit && styles.tab_merit_box} ${demerit && styles.tab_demerit_box} ${point && styles.tab_point_box} ${common && styles.tab_common_box} flex items-center gap-4 text-gray-700`}
>
{merit && (
<>
Expand Down
Loading
Loading