From a76d24f56270691b8ff60a278d04eff8c0178514 Mon Sep 17 00:00:00 2001 From: Arata Date: Sat, 29 Aug 2026 19:51:37 +0900 Subject: [PATCH 1/8] style: update background and text colors for light and dark themes in AppsPromo component --- src/components/Common/AppsPromo/index.module.css | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/Common/AppsPromo/index.module.css b/src/components/Common/AppsPromo/index.module.css index 70f69a9a..9ad062af 100644 --- a/src/components/Common/AppsPromo/index.module.css +++ b/src/components/Common/AppsPromo/index.module.css @@ -3,8 +3,8 @@ overflow: hidden; border-top: 1px solid #d6d6d6; border-bottom: 1px solid #eeeeee; - background: rgb(107 114 128); - color: #ffffff; + background: var(--color-theme-light-border); + color: var(--color-theme-light-text); } .inner { @@ -135,8 +135,8 @@ :global(body.DarkTheme) .appsPromo { border-top-color: #3f3f46; border-bottom-color: #27272a; - background: rgb(107 114 128); - color: #ffffff; + background: var(--color-theme-dark-border); + color: var(--color-theme-dark-text); } @media (max-width: 720px) { From 42f1419c4b73a78f4c293428d52bb1ce1ad7353e Mon Sep 17 00:00:00 2001 From: Arata Date: Sat, 29 Aug 2026 19:52:57 +0900 Subject: [PATCH 2/8] style: unify text color variables for consistency across themes --- src/stories/Foundations.stories.tsx | 1 - src/styles/globals.css | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/stories/Foundations.stories.tsx b/src/stories/Foundations.stories.tsx index cb8b23bd..8cf99680 100644 --- a/src/stories/Foundations.stories.tsx +++ b/src/stories/Foundations.stories.tsx @@ -26,7 +26,6 @@ const themeColors: ColorToken[] = [ ]; const contentColors: ColorToken[] = [ - { name: 'Main text', variable: '--color-text-main', value: '#333' }, { name: 'Secondary text', variable: '--color-text-sub', value: '#767676' }, { name: 'Subtle background', variable: '--color-bg-sub', value: '#f3f3f3' }, { name: 'Border', variable: '--color-border', value: '#ddd' }, diff --git a/src/styles/globals.css b/src/styles/globals.css index cecc8d32..bdefb98e 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -27,7 +27,7 @@ layer(base); :where([data-app-root]) { font-family: 'Geist', sans-serif; - color: var(--color-text-main); + color: var(--color-theme-light-text); line-height: 1.8; } @@ -74,7 +74,6 @@ layer(base); ui-monospace, Menlo, Monaco, 'Cascadia Mono', 'Segoe UI Mono', 'Roboto Mono', 'Oxygen Mono', 'Ubuntu Monospace', 'Source Code Pro', 'Fira Mono', 'Droid Sans Mono', 'Courier New', monospace; - --color-text-main: #333; --color-text-sub: #767676; --color-bg-sub: #f3f3f3; --color-bg-code: #0d1117; From 91bbb47b57dba7fb53b25f2535c0e95ec3ac3c39 Mon Sep 17 00:00:00 2001 From: Arata1202 Date: Sun, 30 Aug 2026 01:06:06 +0900 Subject: [PATCH 3/8] refactor: align theme design tokens --- .../Common/AppsPromo/index.module.css | 8 ++++---- .../FixedContentContainer/index.module.css | 15 +-------------- .../Plugins/CustomHtml/index.module.css | 15 +-------------- .../Plugins/RichText/index.module.css | 15 +-------------- .../Plugins/RichText/index.stories.tsx | 1 - .../Features/Article/index.module.css | 4 ++-- src/components/Features/Article/index.tsx | 2 +- src/stories/Foundations.stories.tsx | 19 +++++++++++++------ src/styles/globals.css | 8 +++++--- src/styles/plugin.css | 6 +++--- 10 files changed, 31 insertions(+), 62 deletions(-) diff --git a/src/components/Common/AppsPromo/index.module.css b/src/components/Common/AppsPromo/index.module.css index 9ad062af..70f69a9a 100644 --- a/src/components/Common/AppsPromo/index.module.css +++ b/src/components/Common/AppsPromo/index.module.css @@ -3,8 +3,8 @@ overflow: hidden; border-top: 1px solid #d6d6d6; border-bottom: 1px solid #eeeeee; - background: var(--color-theme-light-border); - color: var(--color-theme-light-text); + background: rgb(107 114 128); + color: #ffffff; } .inner { @@ -135,8 +135,8 @@ :global(body.DarkTheme) .appsPromo { border-top-color: #3f3f46; border-bottom-color: #27272a; - background: var(--color-theme-dark-border); - color: var(--color-theme-dark-text); + background: rgb(107 114 128); + color: #ffffff; } @media (max-width: 720px) { diff --git a/src/components/Common/Layouts/Container/FixedContentContainer/index.module.css b/src/components/Common/Layouts/Container/FixedContentContainer/index.module.css index d77be1eb..5b6f8db9 100644 --- a/src/components/Common/Layouts/Container/FixedContentContainer/index.module.css +++ b/src/components/Common/Layouts/Container/FixedContentContainer/index.module.css @@ -6,13 +6,6 @@ margin-top: 0; } -.content > h1 { - font-size: var(--font-size-content-heading-1); - font-weight: var(--font-weight-content-heading); - border-bottom: 1px solid var(--color-border); - margin: 2.8rem 0 1rem; -} - .content > h2 { font-size: var(--font-size-content-heading-2); font-weight: var(--font-weight-content-heading); @@ -126,16 +119,10 @@ font-weight: bold; } -.content > blockquote { - border-left: 4px solid var(--color-border); - padding-left: 1rem; - margin: 2rem 0; -} - .content > hr { margin: 4rem 0; height: 1px; - background-color: var(--color-border); + background-color: var(--color-theme-border); border: none; } diff --git a/src/components/Features/Article/Elements/Plugins/CustomHtml/index.module.css b/src/components/Features/Article/Elements/Plugins/CustomHtml/index.module.css index be4f18a5..e80ebace 100644 --- a/src/components/Features/Article/Elements/Plugins/CustomHtml/index.module.css +++ b/src/components/Features/Article/Elements/Plugins/CustomHtml/index.module.css @@ -10,13 +10,6 @@ margin-top: 0; } -.content > h1 { - font-size: var(--font-size-content-heading-1); - font-weight: var(--font-weight-content-heading); - border-bottom: 1px solid var(--color-border); - margin: 2.8rem 0 1rem; -} - .content > h2 { font-size: var(--font-size-content-heading-2); font-weight: var(--font-weight-content-heading); @@ -148,16 +141,10 @@ font-weight: bold; } -.content > blockquote { - border-left: 4px solid var(--color-border); - padding-left: 1rem; - margin: 2rem 0; -} - .content > hr { margin: 4rem 0; height: 1px; - background-color: var(--color-border); + background-color: var(--color-theme-border); border: none; } diff --git a/src/components/Features/Article/Elements/Plugins/RichText/index.module.css b/src/components/Features/Article/Elements/Plugins/RichText/index.module.css index b42f78c5..0571fb41 100644 --- a/src/components/Features/Article/Elements/Plugins/RichText/index.module.css +++ b/src/components/Features/Article/Elements/Plugins/RichText/index.module.css @@ -10,13 +10,6 @@ margin-top: 0; } -.content > h1 { - font-size: var(--font-size-content-heading-1); - font-weight: var(--font-weight-content-heading); - border-bottom: 1px solid var(--color-border); - margin: 2.8rem 0 1rem; -} - .content > h2 { background-color: var(--color-theme-light-border); color: var(--color-theme-light-text); @@ -141,16 +134,10 @@ font-weight: bold; } -.content > blockquote { - border-left: 4px solid var(--color-border); - padding-left: 1rem; - margin: 2rem 0; -} - .content > hr { margin: 4rem 0; height: 1px; - background-color: var(--color-border); + background-color: var(--color-theme-border); border: none; } diff --git a/src/components/Features/Article/Elements/Plugins/RichText/index.stories.tsx b/src/components/Features/Article/Elements/Plugins/RichText/index.stories.tsx index d488061a..da4b7dc2 100644 --- a/src/components/Features/Article/Elements/Plugins/RichText/index.stories.tsx +++ b/src/components/Features/Article/Elements/Plugins/RichText/index.stories.tsx @@ -24,7 +24,6 @@ const tableHtml = ` `; const articleHtml = ` -

記事本文の見出し1

本文には強調リンクが含まれます。

見出し2

段落の余白と行間を確認するための文章です。

diff --git a/src/components/Features/Article/index.module.css b/src/components/Features/Article/index.module.css index 24e558a5..74cecb41 100644 --- a/src/components/Features/Article/index.module.css +++ b/src/components/Features/Article/index.module.css @@ -1,5 +1,5 @@ .title { - font-size: 1.8rem; + font-size: var(--font-size-article-title); font-weight: bold; margin-bottom: 24px; text-align: left; @@ -8,7 +8,7 @@ @media (max-width: 640px) { .title { - font-size: 1.5rem; + font-size: var(--font-size-article-title-mobile); margin-bottom: 20px; } } diff --git a/src/components/Features/Article/index.tsx b/src/components/Features/Article/index.tsx index 2c6b0199..bcd019e7 100644 --- a/src/components/Features/Article/index.tsx +++ b/src/components/Features/Article/index.tsx @@ -82,7 +82,7 @@ export default function ArticleFeature({ data, relatedArticles }: Props) { return ( <> -

+

{data.title}

{data.isSponsored && } diff --git a/src/stories/Foundations.stories.tsx b/src/stories/Foundations.stories.tsx index 8cf99680..5d103581 100644 --- a/src/stories/Foundations.stories.tsx +++ b/src/stories/Foundations.stories.tsx @@ -28,8 +28,6 @@ const themeColors: ColorToken[] = [ const contentColors: ColorToken[] = [ { name: 'Secondary text', variable: '--color-text-sub', value: '#767676' }, { name: 'Subtle background', variable: '--color-bg-sub', value: '#f3f3f3' }, - { name: 'Border', variable: '--color-border', value: '#ddd' }, - { name: 'Dark border', variable: '--color-border-dark', value: '#ccc' }, { name: 'Soft accent background', variable: '--color-accent-soft-bg', value: '#eaf4fc' }, { name: 'Soft accent text', variable: '--color-accent-soft-text', value: '#111827' }, { name: 'Link', variable: '--color-link', value: '#1d4ed8' }, @@ -43,9 +41,15 @@ const contentColors: ColorToken[] = [ const typography: TypographyToken[] = [ { - name: 'Heading 1', - variable: '--font-size-content-heading-1', - value: '2rem', + name: 'Article title', + variable: '--font-size-article-title', + value: '1.8rem', + sample: '記事タイトル', + }, + { + name: 'Article title (mobile)', + variable: '--font-size-article-title-mobile', + value: '1.5rem', sample: '記事タイトル', }, { @@ -159,7 +163,10 @@ function TypographyScale() { {typography.map(({ name, variable, value, sample }) => { const style = { fontSize: `var(${variable})`, - fontWeight: name.startsWith('Heading') ? 'var(--font-weight-content-heading)' : undefined, + fontWeight: + name.startsWith('Heading') || name.startsWith('Article title') + ? 'var(--font-weight-content-heading)' + : undefined, lineHeight: name === 'Body' ? 'var(--line-height-content-body)' : undefined, } satisfies CSSProperties; diff --git a/src/styles/globals.css b/src/styles/globals.css index bdefb98e..ed13ae85 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -37,6 +37,7 @@ layer(base); color: var(--color-theme-light-text); border-color: var(--color-theme-light-border); --tw-ring-color: var(--color-theme-light-border); + --color-theme-border: var(--color-theme-light-border); --color-text-sub: #767676; } @@ -46,6 +47,7 @@ layer(base); color: var(--color-theme-dark-text); border-color: var(--color-theme-dark-border); --tw-ring-color: var(--color-theme-dark-border); + --color-theme-border: var(--color-theme-dark-border); --color-text-sub: #999; } @@ -78,8 +80,6 @@ layer(base); --color-bg-sub: #f3f3f3; --color-bg-code: #0d1117; --color-text-code: #c9d1d9; - --color-border-dark: #ccc; - --color-border: #ddd; --color-focus-ring: #2563eb; --color-accent-soft-bg: #eaf4fc; --color-accent-soft-text: #111827; @@ -93,9 +93,11 @@ layer(base); --color-theme-dark-background: #262626; --color-theme-dark-text: #fff; --color-theme-dark-border: #6b7280; + --color-theme-border: var(--color-theme-light-border); --font-family-content-code: menlo, inconsolata, monospace; --font-size-content-body: 18px; - --font-size-content-heading-1: 2rem; + --font-size-article-title: 1.8rem; + --font-size-article-title-mobile: 1.5rem; --font-size-content-heading-2: 1.6rem; --font-size-content-heading-3: 1.4rem; --font-size-content-heading-4: 1.2rem; diff --git a/src/styles/plugin.css b/src/styles/plugin.css index 4c78438f..e75be01f 100644 --- a/src/styles/plugin.css +++ b/src/styles/plugin.css @@ -13,7 +13,7 @@ .underline_code { background-color: #f7f7fc; - border: 1px solid var(--color-border); + border: 1px solid var(--color-theme-border); border-radius: 3px; color: #2b2c30; margin: 0 2px; @@ -34,7 +34,7 @@ table { } table tr th { - border: 1px solid var(--color-border-dark); + border: 1px solid var(--color-theme-border); background-color: var(--color-accent-soft-bg) !important; word-wrap: break-word; overflow-wrap: break-word; @@ -42,7 +42,7 @@ table tr th { } table tr td { - border: 1px solid var(--color-border-dark); + border: 1px solid var(--color-theme-border); word-wrap: break-word; overflow-wrap: break-word; white-space: normal; From 7240e3a5e0a7c1482090626f865f2e84b75f7d9d Mon Sep 17 00:00:00 2001 From: Arata1202 Date: Sun, 30 Aug 2026 01:43:59 +0900 Subject: [PATCH 4/8] style: retain themed app promo colors --- src/components/Common/AppsPromo/index.module.css | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/Common/AppsPromo/index.module.css b/src/components/Common/AppsPromo/index.module.css index 70f69a9a..9ad062af 100644 --- a/src/components/Common/AppsPromo/index.module.css +++ b/src/components/Common/AppsPromo/index.module.css @@ -3,8 +3,8 @@ overflow: hidden; border-top: 1px solid #d6d6d6; border-bottom: 1px solid #eeeeee; - background: rgb(107 114 128); - color: #ffffff; + background: var(--color-theme-light-border); + color: var(--color-theme-light-text); } .inner { @@ -135,8 +135,8 @@ :global(body.DarkTheme) .appsPromo { border-top-color: #3f3f46; border-bottom-color: #27272a; - background: rgb(107 114 128); - color: #ffffff; + background: var(--color-theme-dark-border); + color: var(--color-theme-dark-text); } @media (max-width: 720px) { From 45ab743b27117c482a371bb5a1773f78bdac1ac7 Mon Sep 17 00:00:00 2001 From: Arata1202 Date: Sun, 30 Aug 2026 01:49:05 +0900 Subject: [PATCH 5/8] test: align article plugin stories with usage --- .../Plugins/CustomHtml/index.stories.tsx | 90 ++++++++++++------- .../Plugins/RichText/index.stories.tsx | 1 + 2 files changed, 60 insertions(+), 31 deletions(-) diff --git a/src/components/Features/Article/Elements/Plugins/CustomHtml/index.stories.tsx b/src/components/Features/Article/Elements/Plugins/CustomHtml/index.stories.tsx index 67eebf2c..82d5b68a 100644 --- a/src/components/Features/Article/Elements/Plugins/CustomHtml/index.stories.tsx +++ b/src/components/Features/Article/Elements/Plugins/CustomHtml/index.stories.tsx @@ -1,34 +1,48 @@ import type { Meta, StoryObj } from '@storybook/nextjs-vite'; -import { expect, userEvent, waitFor, within } from 'storybook/test'; +import { expect, waitFor, within } from 'storybook/test'; import CustomHtml from '.'; import '@/styles/plugin.css'; -const articleHtml = ` -

カスタムHTMLで挿入される記事本文の表示例です。強調外部リンクを含みます。

-

カスタムHTMLの見出し

-

本文の余白、行間、リンク色などが本番の記事画面と同じことを確認します。

-
-
export function greeting(name: string) {
-  return \`こんにちは、\${name}さん\`;
-}
+const affiliateLinkHtml = ` + -

表示できる要素

-
    -
  • 箇条書き
  • -
  • コードブロック
  • -
  • 引用とテーブル
  • -
-

引用文の背景、余白、アイコンを確認します。

- - - -
項目内容
表示元カスタムHTML
+`; + +const embeddedMapHtml = ` + `; const meta = { title: 'Content/Article Plugins/Custom HTML', component: CustomHtml, - args: { html: articleHtml }, decorators: [ (Story) => (
@@ -39,7 +53,8 @@ const meta = { parameters: { docs: { description: { - component: '記事本文へ挿入される、サニタイズ済みカスタムHTMLの本番相当表示を確認します。', + component: + 'アフィリエイトリンクや外部埋め込みなど、記事で実際に使うカスタムHTMLを確認します。', }, }, }, @@ -49,22 +64,35 @@ const meta = { export default meta; type Story = StoryObj; -export const ArticleContent: Story = { +export const AffiliateLink: Story = { + args: { html: affiliateLinkHtml }, play: async ({ canvasElement }) => { const canvas = within(canvasElement); - const externalLink = canvas.getByRole('link', { name: '外部リンク' }); - const wrapButton = await canvas.findByRole('button', { name: 'コードを折り返す' }); + const amazonLink = canvas.getByRole('link', { name: 'Amazonで見る' }); + const previousButton = await canvas.findByRole('button', { name: '前の画像を表示' }); + const nextButton = canvas.getByRole('button', { name: '次の画像を表示' }); await waitFor(() => { - expect(externalLink).toHaveAttribute('target', '_blank'); - expect(externalLink).toHaveAttribute('rel', 'noopener noreferrer'); + expect(amazonLink).toHaveAttribute('target', '_blank'); + expect(amazonLink).toHaveAttribute('rel', 'noopener noreferrer'); }); - - await userEvent.click(wrapButton); - await expect(wrapButton).toHaveAttribute('aria-pressed', 'true'); + await expect(previousButton).toHaveAttribute('role', 'button'); + await expect(nextButton).toHaveAttribute('role', 'button'); }, }; -export const Mobile: Story = { +export const AffiliateLinkMobile: Story = { + args: { html: affiliateLinkHtml }, globals: { viewport: { value: 'mobile1', isRotated: false } }, }; + +export const EmbeddedMap: Story = { + args: { html: embeddedMapHtml }, + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + const map = canvas.getByTitle('東京周辺のGoogle Map'); + + await expect(map).toHaveAttribute('loading', 'lazy'); + await expect(getComputedStyle(map).width).not.toBe('600px'); + }, +}; diff --git a/src/components/Features/Article/Elements/Plugins/RichText/index.stories.tsx b/src/components/Features/Article/Elements/Plugins/RichText/index.stories.tsx index da4b7dc2..f0ec8ddd 100644 --- a/src/components/Features/Article/Elements/Plugins/RichText/index.stories.tsx +++ b/src/components/Features/Article/Elements/Plugins/RichText/index.stories.tsx @@ -29,6 +29,7 @@ const articleHtml = `

段落の余白と行間を確認するための文章です。

見出し3

  • 箇条書きの項目
  • もうひとつの項目
+

見出し4

  1. 番号付きの項目
  2. 次の手順

引用として表示される文章です。

記事本文のサンプル画像
画像のキャプション
From 6f8c8fbddc41efefe28a80023bb4b2865c7d5767 Mon Sep 17 00:00:00 2001 From: Arata1202 Date: Sun, 30 Aug 2026 01:51:34 +0900 Subject: [PATCH 6/8] test: focus custom html story on maps --- .../Plugins/CustomHtml/index.stories.tsx | 58 ++----------------- 1 file changed, 5 insertions(+), 53 deletions(-) diff --git a/src/components/Features/Article/Elements/Plugins/CustomHtml/index.stories.tsx b/src/components/Features/Article/Elements/Plugins/CustomHtml/index.stories.tsx index 82d5b68a..d6384ed4 100644 --- a/src/components/Features/Article/Elements/Plugins/CustomHtml/index.stories.tsx +++ b/src/components/Features/Article/Elements/Plugins/CustomHtml/index.stories.tsx @@ -1,34 +1,9 @@ import type { Meta, StoryObj } from '@storybook/nextjs-vite'; -import { expect, waitFor, within } from 'storybook/test'; +import { expect, within } from 'storybook/test'; import CustomHtml from '.'; import '@/styles/plugin.css'; -const affiliateLinkHtml = ` - -`; - -const embeddedMapHtml = ` +const googleMapHtml = `