-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #18 from ReoHakase/16/add-prefecture-state-bar
都道府県の選択状態を表示するコンポーネント`<PrefectureStateBar>`を実装した
- Loading branch information
Showing
7 changed files
with
240 additions
and
36 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
53 changes: 53 additions & 0 deletions
53
apps/web/src/features/navigation/components/PrefectureStateBar/PrefectureClearButton.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
'use client'; | ||
|
||
import { X } from 'lucide-react'; | ||
import { usePathname } from 'next/navigation'; | ||
import { ReactNode } from 'react'; | ||
import { Link } from '@/components/Link/Link'; | ||
import type { LinkProps } from '@/components/Link/Link'; | ||
import { css, cx } from 'styled-system/css'; | ||
|
||
export type PrefectureClearButtonProps<T> = Omit<LinkProps<T>, 'href' | 'children'>; | ||
|
||
/** | ||
* 都道府県選択をクリアするためのボタン。 | ||
* | ||
* @param props 追加のプロパティ | ||
* @returns 都道府県選択をクリアするためのボタン | ||
*/ | ||
export const PrefectureClearButton = <T,>({ className, ...props }: PrefectureClearButtonProps<T>): ReactNode => { | ||
// searchParamsは含まない | ||
const pathname = usePathname(); | ||
return ( | ||
<Link | ||
href={pathname} | ||
className={cx( | ||
css({ | ||
display: 'flex', | ||
h: '44px', | ||
justifyContent: 'center', | ||
alignItems: 'center', | ||
fontFamily: 'heading', | ||
fontWeight: 'bold', | ||
px: '4', | ||
py: '2', | ||
gap: '1', | ||
bg: 'keyplate.12', | ||
color: 'keyplate.1', | ||
rounded: 'full', | ||
}), | ||
className, | ||
)} | ||
{...props} | ||
> | ||
<X | ||
className={css({ | ||
display: 'inline', | ||
w: '4', | ||
h: '4', | ||
})} | ||
/> | ||
クリア | ||
</Link> | ||
); | ||
}; |
27 changes: 27 additions & 0 deletions
27
apps/web/src/features/navigation/components/PrefectureStateBar/PrefectureCount.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
'use client'; | ||
|
||
import { useSearchParams } from 'next/navigation'; | ||
import { ReactNode } from 'react'; | ||
import { useMemo } from 'react'; | ||
import { prefCodesSchema } from '@/models/prefCode'; | ||
import type { PrefCode } from '@/models/prefCode'; | ||
|
||
/** | ||
* 都道府県の数を表示するコンポーネントです。 | ||
* | ||
* @returns {ReactNode} 都道府県の数を表示するためのコンポーネント | ||
*/ | ||
export const PrefectureCount = (): ReactNode => { | ||
const searchParams = useSearchParams(); | ||
const count = useMemo(() => { | ||
const params = new URLSearchParams(searchParams.toString()); | ||
const currentPrefCodes = prefCodesSchema.parse( | ||
params | ||
.getAll('prefCodes') | ||
.map((str) => str.split(',')) | ||
.flat(), | ||
) as PrefCode[]; | ||
return currentPrefCodes.length; | ||
}, [searchParams]); | ||
return <>{count}</>; | ||
}; |
35 changes: 35 additions & 0 deletions
35
.../web/src/features/navigation/components/PrefectureStateBar/PrefectureStateBar.stories.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import type { Meta, StoryObj } from '@storybook/react'; | ||
import { expect, within } from '@storybook/test'; | ||
import { PrefectureStateBar } from './PrefectureStateBar'; | ||
|
||
type Story = StoryObj<typeof PrefectureStateBar>; | ||
|
||
const meta: Meta<typeof PrefectureStateBar> = { | ||
component: PrefectureStateBar, | ||
tags: ['autodocs'], | ||
parameters: { | ||
nextjs: { | ||
appDirectory: true, | ||
navigation: { | ||
pathname: '/all', | ||
query: { | ||
prefCodes: '8,12,13,14', | ||
}, | ||
}, | ||
}, | ||
}, | ||
argTypes: {}, | ||
}; | ||
|
||
export default meta; | ||
|
||
export const Default: Story = { | ||
play: async ({ canvasElement }) => { | ||
const canvas = within(canvasElement); | ||
const clearButton = canvas.getByRole('link'); | ||
const heading = canvas.getByRole('heading'); | ||
|
||
expect(heading).toHaveTextContent('4つの都道府県を選択中'); | ||
expect(clearButton.getAttribute('href')).toBe('/all'); | ||
}, | ||
}; |
106 changes: 106 additions & 0 deletions
106
apps/web/src/features/navigation/components/PrefectureStateBar/PrefectureStateBar.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
import { ArrowDown } from 'lucide-react'; | ||
import { ReactNode, ComponentPropsWithoutRef } from 'react'; | ||
import { Suspense } from 'react'; | ||
import { Skeleton } from '../Skeleton/Skeleton'; | ||
import { PrefectureClearButton } from './PrefectureClearButton'; | ||
import { PrefectureCount } from './PrefectureCount'; | ||
import { css, cx } from 'styled-system/css'; | ||
|
||
export const SELECTION_STATE_LABEL_ID = 'selection-state-label' as const; | ||
|
||
export type PrefectureStateBarProps = Omit<ComponentPropsWithoutRef<'div'>, 'children'>; | ||
|
||
/** | ||
* 選択中の都道府県の状態を表示するバー。 | ||
* | ||
* @param children 子要素 | ||
* @param props 追加のプロパティ | ||
* @returns 都道府県の状態を表示するバー | ||
*/ | ||
export const PrefectureStateBar = ({ className, ...props }: PrefectureStateBarProps): ReactNode => { | ||
return ( | ||
<div | ||
id={SELECTION_STATE_LABEL_ID} | ||
className={cx( | ||
css({ | ||
bg: 'keyplate.1', | ||
border: '1px solid', | ||
borderColor: 'keyplate.6', | ||
rounded: '26px', // 内側のクリアボタンに合わせる | ||
display: 'flex', | ||
flexDir: 'row', | ||
justifyContent: 'start', | ||
alignItems: 'center', | ||
p: '2', | ||
gap: '4', | ||
}), | ||
className, | ||
)} | ||
{...props} | ||
> | ||
<div | ||
id={SELECTION_STATE_LABEL_ID} | ||
className={cx( | ||
css({ | ||
flexGrow: '1', | ||
display: 'flex', | ||
flexDir: 'row', | ||
justifyContent: 'start', | ||
alignItems: 'center', | ||
pl: '3', | ||
gap: '3', | ||
}), | ||
className, | ||
)} | ||
{...props} | ||
> | ||
<ArrowDown /> | ||
<h2 id={SELECTION_STATE_LABEL_ID}> | ||
<Suspense | ||
fallback={ | ||
<Skeleton | ||
className={css({ | ||
w: '3', | ||
})} | ||
/> | ||
} | ||
> | ||
<PrefectureCount /> | ||
</Suspense> | ||
つの都道府県を選択中 | ||
</h2> | ||
<div | ||
aria-hidden | ||
className={css({ | ||
pos: 'relative', | ||
w: '3', | ||
h: '3', | ||
})} | ||
> | ||
<div | ||
className={css({ | ||
pos: 'absolute', | ||
animation: 'ping', | ||
w: 'full', | ||
h: 'full', | ||
bg: 'info.6', | ||
rounded: 'full', | ||
})} | ||
/> | ||
<div | ||
className={css({ | ||
pos: 'relative', | ||
w: 'full', | ||
h: 'full', | ||
bg: 'info.9', | ||
rounded: 'full', | ||
border: '2px solid', | ||
borderColor: 'info.7', | ||
})} | ||
/> | ||
</div> | ||
</div> | ||
<PrefectureClearButton /> | ||
</div> | ||
); | ||
}; |
Oops, something went wrong.