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
2 changes: 1 addition & 1 deletion frontend/src/components/brand/mongle-icon.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { MongleIcon } from '@/components/brand/mongle-logo'
import { MongleIcon } from '@/components/brand/mongle-icon'
import type { Meta, StoryObj } from '@storybook/react-vite'

const meta = {
Expand Down
15 changes: 15 additions & 0 deletions frontend/src/components/brand/mongle-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { cn } from '@/lib/utils'

export function MongleIcon({ className }: { className?: string }) {
return (
<svg
viewBox="0 0 24 24"
fill="currentColor"
aria-hidden
className={cn('size-6 shrink-0', className)}
>
<circle cx="9.5" cy="12" r="7.5" />
<circle cx="16.5" cy="9" r="4.5" />
</svg>
)
}
15 changes: 1 addition & 14 deletions frontend/src/components/brand/mongle-logo.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,6 @@
import { MongleIcon } from '@/components/brand/mongle-icon'
import { cn } from '@/lib/utils'

export function MongleIcon({ className }: { className?: string }) {
return (
<svg
viewBox="0 0 24 24"
fill="currentColor"
aria-hidden
className={cn('size-6 shrink-0', className)}
>
<circle cx="9.5" cy="12" r="7.5" />
<circle cx="16.5" cy="9" r="4.5" />
</svg>
)
}

export function MongleLogo({
className,
iconClassName,
Expand Down
17 changes: 17 additions & 0 deletions frontend/src/components/person/field-label.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type { Meta, StoryObj } from '@storybook/react-vite'
import { FieldLabel } from '@/components/person/field-label'

const meta = {
title: 'Person/FieldLabel',
component: FieldLabel,
tags: ['autodocs'],
args: {
children: '만남 태그',
},
} satisfies Meta<typeof FieldLabel>

export default meta

type Story = StoryObj<typeof meta>

export const Default: Story = {}
15 changes: 15 additions & 0 deletions frontend/src/components/person/field-label.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import type { ComponentProps } from 'react'
import { Label } from '@/components/ui/label'
import { cn } from '@/lib/utils'

export function FieldLabel({
className,
children,
...props
}: ComponentProps<typeof Label>) {
return (
<Label className={cn('font-extrabold', className)} {...props}>
{children}
</Label>
)
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useState } from 'react'
import type { ComponentProps } from 'react'
import type { Meta, StoryObj } from '@storybook/react-vite'
import { ListField, RelationTypeField } from '@/components/person/person-fields'
import { ListField } from '@/components/person/list-field'

function ListFieldDemo(args: ComponentProps<typeof ListField>) {
const [items, setItems] = useState(args.items)
Expand All @@ -12,19 +12,8 @@ function ListFieldDemo(args: ComponentProps<typeof ListField>) {
)
}

function RelationTypeDemo({ initial = '' }: { initial?: string }) {
const [value, setValue] = useState(initial)
return (
<div className="max-w-md">
<RelationTypeField value={value} onChange={setValue} />
</div>
)
}

// 한 파일에 ListField/RelationTypeField 두 컴포넌트를 담는다(원본이 person-fields.tsx 한 파일).
// meta.component은 ListField 기준이고, RelationType 스토리는 render로 직접 그린다.
const meta = {
title: 'Person/PersonFields',
title: 'Person/ListField',
component: ListField,
tags: ['autodocs'],
args: {
Expand Down Expand Up @@ -62,11 +51,3 @@ export const ListFieldCompact: Story = {
export const ListFieldMaxItems: Story = {
args: { maxItems: 3, items: ['하나', '둘', '셋'] },
}

export const RelationTypeDefault: Story = {
render: () => <RelationTypeDemo />,
}

export const RelationTypeSelected: Story = {
render: () => <RelationTypeDemo initial="친구" />,
}
Original file line number Diff line number Diff line change
@@ -1,25 +1,10 @@
import type { ComponentProps } from 'react'
import { useState } from 'react'
import { X } from 'lucide-react'
import { Label } from '@/components/ui/label'
import { Button } from '@/components/ui/button'
import { ListGroupInset } from '@/components/ui/list-group'
import { TagChip } from '@/components/ui/tag-chip'
import { FieldLabel } from '@/components/person/field-label'
import { isImeComposing } from '@/lib/keyboard'
import { cn } from '@/lib/utils'

function FieldLabel({
className,
children,
...props
}: ComponentProps<typeof Label>) {
return (
<Label className={cn('font-extrabold', className)} {...props}>
{children}
</Label>
)
}

export function ListField({
label,
items,
Expand Down Expand Up @@ -140,55 +125,3 @@ export function ListField({
</div>
)
}

export const RELATION_TYPE_SUGGESTIONS = [
'친구',
'회사 동료',
'가족',
'연인',
'스터디원',
'이웃',
'지인',
] as const

export function RelationTypeField({
value,
onChange,
inset = false,
hideLabel = false,
}: {
value: string
onChange: (value: string) => void
inset?: boolean
hideLabel?: boolean
}) {
const chips = (
<div className={cn('flex flex-wrap gap-2', !hideLabel && !inset && 'mt-2')}>
{RELATION_TYPE_SUGGESTIONS.map((suggestion) => (
<TagChip
key={suggestion}
tone="foreground"
surface="card"
hover
selected={value === suggestion}
onClick={() => {
onChange(value === suggestion ? '' : suggestion)
}}
>
{suggestion}
</TagChip>
))}
</div>
)

return (
<div>
{hideLabel ? null : <FieldLabel>만남 태그</FieldLabel>}
{inset ? (
<ListGroupInset className="mt-2 p-2">{chips}</ListGroupInset>
) : (
chips
)}
</div>
)
}
3 changes: 2 additions & 1 deletion frontend/src/components/person/person-edit-form.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { useRef, useState } from 'react'
import type { FormEvent } from 'react'
import { DateWheel } from '@/components/person/date-wheel'
import { ListField, RelationTypeField } from '@/components/person/person-fields'
import { ListField } from '@/components/person/list-field'
import { RelationTypeField } from '@/components/person/relation-type-field'
import {
GENDER_OPTIONS,
ProfileHero,
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/person/person-tab-nav.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ListGroupInset } from '@/components/ui/list-group'
import { ListGroupInset } from '@/components/ui/list-group-inset'
import { SegmentedControl } from '@/components/ui/segmented-control'
import type { PersonView } from '@/stackflow/stackflow.config'

Expand Down
34 changes: 34 additions & 0 deletions frontend/src/components/person/relation-type-field.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { useState } from 'react'
import type { Meta, StoryObj } from '@storybook/react-vite'
import { RelationTypeField } from '@/components/person/relation-type-field'

function RelationTypeDemo({ initial = '' }: { initial?: string }) {
const [value, setValue] = useState(initial)
return (
<div className="max-w-md">
<RelationTypeField value={value} onChange={setValue} />
</div>
)
}

const meta = {
title: 'Person/RelationTypeField',
component: RelationTypeField,
tags: ['autodocs'],
args: {
value: '',
onChange: () => {},
},
} satisfies Meta<typeof RelationTypeField>

export default meta

type Story = StoryObj<typeof meta>

export const RelationTypeDefault: Story = {
render: () => <RelationTypeDemo />,
}

export const RelationTypeSelected: Story = {
render: () => <RelationTypeDemo initial="친구" />,
}
56 changes: 56 additions & 0 deletions frontend/src/components/person/relation-type-field.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { FieldLabel } from '@/components/person/field-label'
import { ListGroupInset } from '@/components/ui/list-group-inset'
import { TagChip } from '@/components/ui/tag-chip'
import { cn } from '@/lib/utils'

export const RELATION_TYPE_SUGGESTIONS = [
'친구',
'회사 동료',
'가족',
'연인',
'스터디원',
'이웃',
'지인',
] as const

export function RelationTypeField({
value,
onChange,
inset = false,
hideLabel = false,
}: {
value: string
onChange: (value: string) => void
inset?: boolean
hideLabel?: boolean
}) {
const chips = (
<div className={cn('flex flex-wrap gap-2', !hideLabel && !inset && 'mt-2')}>
{RELATION_TYPE_SUGGESTIONS.map((suggestion) => (
<TagChip
key={suggestion}
tone="foreground"
surface="card"
hover
selected={value === suggestion}
onClick={() => {
onChange(value === suggestion ? '' : suggestion)
}}
>
{suggestion}
</TagChip>
))}
</div>
)

return (
<div>
{hideLabel ? null : <FieldLabel>만남 태그</FieldLabel>}
{inset ? (
<ListGroupInset className="mt-2 p-2">{chips}</ListGroupInset>
) : (
chips
)}
</div>
)
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ChevronRight } from 'lucide-react'
import { ListGroupItem } from '@/components/ui/list-group'
import { ListGroupItem } from '@/components/ui/list-group-item'

export function SettingsNavigationItem({
label,
Expand Down
Loading
Loading