@@ -115,7 +136,7 @@ export default function FormField<
{showCounterRight && typeof counterMax === 'number' && (
-
+
{currentLen}/{counterMax}
)}
diff --git a/src/shared/ui/input/base.tsx b/src/shared/ui/input/base.tsx
index c0bbffae..1d6d667b 100644
--- a/src/shared/ui/input/base.tsx
+++ b/src/shared/ui/input/base.tsx
@@ -40,6 +40,9 @@ const inputVariants = cva(
boxed: 'rounded-100 border px-150 border-border-default',
bare: 'border-0 rounded-none px-0 focus-visible:outline-none shadow-none',
},
+ disabled: {
+ true: 'bg-background-disabled text-text-disabled border-border-disabled cursor-not-allowed',
+ },
},
defaultVariants: {
color: 'default',
@@ -64,7 +67,16 @@ export const BaseInput = React.forwardRef
(
return (
{
onChange?.(e);
diff --git a/src/shared/ui/toggle/group.tsx b/src/shared/ui/toggle/group.tsx
index 45076634..7a2c06da 100644
--- a/src/shared/ui/toggle/group.tsx
+++ b/src/shared/ui/toggle/group.tsx
@@ -1,3 +1,4 @@
+import type { ComponentType, ReactNode } from 'react';
import ToggleButton from './button';
export interface ToggleOption {
@@ -5,20 +6,63 @@ export interface ToggleOption {
label: string;
}
-export interface ToggleGroupProps {
+interface MultiProps {
options: ToggleOption[];
+ multiple?: true;
value?: string[];
onChange?: (v: string[]) => void;
+ renderItem?: ComponentType;
}
-function ToggleGroup({ options, value, onChange }: ToggleGroupProps) {
- const selected = value ?? [];
+interface SingleProps {
+ options: ToggleOption[];
+ multiple: false;
+ value?: string;
+ onChange?: (v: string | undefined) => void;
+ allowDeselect?: boolean;
+ emptyValue?: string | undefined;
+ renderItem?: ComponentType;
+}
+
+export type ToggleGroupProps = MultiProps | SingleProps;
+
+export interface ItemRendererProps {
+ pressed: boolean;
+ onPress: () => void;
+ children: ReactNode;
+}
+
+function ToggleGroup({ pressed, onPress, children }: ItemRendererProps) {
+ return (
+
+ {children}
+
+ );
+}
+
+function GroupItems(props: ToggleGroupProps) {
+ const { options } = props;
+ const isMulti = props.multiple !== false;
+ const Item = props.renderItem ?? ToggleGroup;
+
+ const selectedSet = new Set(
+ isMulti ? (props.value ?? []) : props.value ? [props.value] : [],
+ );
const toggle = (key: string) => {
- const next = selected.includes(key)
- ? selected.filter((x) => x !== key)
- : [...selected, key];
- onChange?.(next);
+ if (isMulti) {
+ const curr = (props.value ?? []) as string[];
+ const next = curr.includes(key)
+ ? curr.filter((x) => x !== key)
+ : [...curr, key];
+ (props.onChange as ((v: string[]) => void) | undefined)?.(next);
+ } else {
+ const curr = props.value as string | undefined;
+ const allowDeselect = props.allowDeselect ?? true;
+ const cleared = 'emptyValue' in props ? props.emptyValue : undefined;
+ const next = curr === key ? (allowDeselect ? cleared : key) : key;
+ (props.onChange as ((v: string | undefined) => void) | undefined)?.(next);
+ }
};
return (
@@ -28,17 +72,12 @@ function ToggleGroup({ options, value, onChange }: ToggleGroupProps) {
aria-label="toggle-group"
>
{options.map(({ value: v, label }) => (
- toggle(v)}
- >
+ - toggle(v)}>
{label}
-
+
))}
);
}
-export default ToggleGroup;
+export default GroupItems;
diff --git a/src/shared/ui/toggle/index.tsx b/src/shared/ui/toggle/index.tsx
index 8d9c83e8..e3372b09 100644
--- a/src/shared/ui/toggle/index.tsx
+++ b/src/shared/ui/toggle/index.tsx
@@ -1,3 +1,3 @@
export * from './switch';
export { default as ToggleButton } from './button';
-export { default as ToggleGroup } from './group';
+export { default as GroupItems } from './group';
diff --git a/src/stories/ui/group-study-thumbnail-input.stories.tsx b/src/stories/ui/group-study-thumbnail-input.stories.tsx
index 948fd35d..08422ac7 100644
--- a/src/stories/ui/group-study-thumbnail-input.stories.tsx
+++ b/src/stories/ui/group-study-thumbnail-input.stories.tsx
@@ -22,8 +22,9 @@ type Story = StoryObj
;
export const Default: Story = {
render: () => {
- const [image, setImage] = useState(undefined);
+ const [file, setFile] = useState(null);
+ const image = file ? URL.createObjectURL(file) : undefined;
- return ;
+ return ;
},
};
diff --git a/src/widgets/home/sidebar.tsx b/src/widgets/home/sidebar.tsx
index 904d8d0f..a32dd466 100644
--- a/src/widgets/home/sidebar.tsx
+++ b/src/widgets/home/sidebar.tsx
@@ -2,6 +2,7 @@ import Image from 'next/image';
import Link from 'next/link';
import { getUserProfileInServer } from '@/entities/user/api/get-user-profile.server';
import MyProfileCard from '@/entities/user/ui/my-profile-card';
+import OpenGroupStudyModal from '@/features/study/group/ui/open-group-modal';
import StartStudyModal from '@/features/study/participation/ui/start-study-modal';
import { getServerCookie } from '@/shared/lib/server-cookie';
import Calendar from '@/widgets/home/calendar';
@@ -59,6 +60,21 @@ export default async function Sidebar() {
}
/>
)}
+ {/* todo: 편하게 확인하시라고 추가했습니다. 이후 목록 추가되고 연결되면 제가 지워서 커밋 올리도록 하겠습니다. */}
+ {/*
+
+
+ 그룹 스터디를 시작해 보세요!
+
+
+ 스터디 신청하기
+
+
+
+ }
+ /> */}