Skip to content

Commit 4d6cff1

Browse files
committed
style: make iom link less intrusive
1 parent c10ba05 commit 4d6cff1

3 files changed

Lines changed: 188 additions & 170 deletions

File tree

components/EditForm.tsx

Lines changed: 59 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
Popover,
1414
PopoverContent,
1515
PopoverTrigger,
16+
AnimatedCount,
1617
} from "@betterinternship/components";
1718
import { Calendar } from "@/components/ui/calendar";
1819
import {
@@ -25,6 +26,7 @@ import * as RadioGroup from "@radix-ui/react-radio-group";
2526
import {
2627
CalendarDays,
2728
Check,
29+
CheckCheck,
2830
ChevronDown,
2931
ChevronLeft,
3032
ChevronRight,
@@ -33,14 +35,14 @@ import {
3335
Minus,
3436
} from "lucide-react";
3537
import * as React from "react";
36-
import { createContext, useContext, useRef } from "react";
38+
import { createContext, useContext, useEffect, useRef } from "react";
3739
import "react-datepicker/dist/react-datepicker.css";
3840
import { GroupableRadioDropdown } from "./ui/dropdown";
3941
import { Input } from "@betterinternship/components";
4042
import { Tooltip } from "react-tooltip";
4143
import { Textarea } from "./ui/textarea";
4244
import { Matcher } from "react-day-picker";
43-
import { AnimatePresence, motion } from "framer-motion";
45+
import { AnimatePresence, motion, useReducedMotion } from "framer-motion";
4446
import { useBlurTransition } from "./animata/blur";
4547

4648
interface EditFormContext<T extends IFormData> {
@@ -439,14 +441,26 @@ export const FormCheckbox = ({
439441
interface FormCheckBoxGroupProps extends React.InputHTMLAttributes<HTMLInputElement> {
440442
options: { value: string | number; label: string; description?: string }[];
441443
values: (string | number)[];
442-
setter: (value: any) => void;
444+
setter: (values: (string | number)[]) => void;
443445
label?: string;
444446
required?: boolean;
445447
className?: string;
446448
tooltip?: string;
447449
tooltipId?: string;
450+
/** Multi-select hint shown above the options. Pass `null` to hide it. */
451+
hint?: React.ReactNode;
452+
/** Columns on md+ screens. Defaults to 3. */
453+
columns?: 1 | 2 | 3;
454+
/** Fired when a single option is toggled, before the setter runs. */
455+
onToggle?: (value: string | number, checked: boolean) => void;
448456
}
449457

458+
const GRID_COLS: Record<1 | 2 | 3, string> = {
459+
1: "",
460+
2: "md:grid-cols-2",
461+
3: "md:grid-cols-3",
462+
};
463+
450464
export const FormCheckBoxGroup = ({
451465
options,
452466
values,
@@ -456,16 +470,23 @@ export const FormCheckBoxGroup = ({
456470
className,
457471
tooltip,
458472
tooltipId,
473+
hint = "Select all that apply",
474+
columns = 3,
475+
onToggle,
459476
...props
460477
}: FormCheckBoxGroupProps) => {
461478
const handleValueChange = (optionValue: string | number) => {
462-
if (values.includes(optionValue)) {
463-
setter(values.filter((v) => v !== optionValue));
464-
} else {
465-
setter([...values, optionValue]);
466-
}
479+
const willBeChecked = !values.includes(optionValue);
480+
onToggle?.(optionValue, willBeChecked);
481+
setter(
482+
willBeChecked
483+
? [...values, optionValue]
484+
: values.filter((v) => v !== optionValue),
485+
);
467486
};
468487

488+
const blurTransition = useBlurTransition();
489+
469490
return (
470491
<div className={cn("space-y-3", className)}>
471492
{label && (
@@ -477,16 +498,43 @@ export const FormCheckBoxGroup = ({
477498
/>
478499
)}
479500

480-
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
501+
{(hint || values.length > 0) && (
502+
<div className="flex items-center gap-2 text-xs">
503+
{hint && (
504+
<span className="inline-flex items-center gap-1 rounded-full bg-muted px-2 py-0.5 font-medium text-muted-foreground">
505+
<CheckCheck className="h-3 w-3" />
506+
{hint}
507+
</span>
508+
)}
509+
<AnimatePresence>
510+
{values.length > 0 && (
511+
<motion.span
512+
className="font-medium text-primary"
513+
{...blurTransition}
514+
>
515+
<AnimatedCount value={values.length} /> selected
516+
</motion.span>
517+
)}
518+
</AnimatePresence>
519+
</div>
520+
)}
521+
522+
<div className={cn("grid grid-cols-1 gap-4", GRID_COLS[columns])}>
481523
{options.map((option) => {
482524
const isChecked = values.includes(option.value);
483525

484526
return (
485527
<div
486528
key={option.value}
529+
role="checkbox"
530+
aria-checked={isChecked}
487531
onClick={() => handleValueChange(option.value)}
488-
className={`flex items-start gap-4 p-3 border rounded-[0.33em] transition-colors cursor-pointer h-fit
489-
${isChecked ? "border-primary border-opacity-85" : "border-gray-200 hover:border-gray-300"}`}
532+
className={cn(
533+
"flex items-start gap-3 p-3 border rounded-[0.33em] transition-colors cursor-pointer h-fit",
534+
isChecked
535+
? "border-primary border-opacity-85 bg-primary/5"
536+
: "border-gray-200 hover:border-gray-300 hover:bg-gray-50",
537+
)}
490538
>
491539
<FormCheckbox checked={isChecked ?? false} />
492540
<div className="grid grid-rows-1 md:grid-rows-2">

components/features/hire/listings/create-job-steps/BasicStep.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import { FormInput } from "@/components/EditForm";
44
import { GroupableRadioDropdown } from "@/components/ui/dropdown";
55
import { Job } from "@/lib/db/db.types";
6-
import { Card, PageHeader } from "@betterinternship/components";
6+
import { AnimatedCount, Card, PageHeader } from "@betterinternship/components";
77
import { Input } from "@betterinternship/components";
88
import { Textarea } from "@/components/ui/textarea";
99
import { BasicStepIllustration } from "./illustrations/BasicStepIllustration";
@@ -100,7 +100,8 @@ const BasicStep = ({
100100
className="h-10"
101101
/>
102102
<p className="text-xs text-muted-foreground tabular-nums shrink-0 text-right">
103-
{titleLength}/100
103+
<AnimatedCount value={titleLength} />
104+
/100
104105
</p>
105106
</div>
106107

0 commit comments

Comments
 (0)