A feedback window with a topic, a subject, a message and a short thank-you after sending.
registry/macos/blocks/feedback-01/feedback-01.tsx
"use client"
import * as React from "react"
import { CheckIcon } from "lucide-react"
import { cn } from "@/lib/utils"
import { Button } from "@/registry/macos/ui/button"
import { Checkbox } from "@/registry/macos/ui/checkbox"
import { IconTile } from "@/registry/macos/ui/icon-tile"
import { Input } from "@/registry/macos/ui/input"
import { Label } from "@/registry/macos/ui/label"
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/registry/macos/ui/select"
import { Textarea } from "@/registry/macos/ui/textarea"
import {
Window,
WindowContent,
WindowControls,
WindowMain,
WindowTitle,
WindowTitlebar,
} from "@/registry/macos/ui/window"
const topics = {
bug: "Bug",
idea: "Idea",
question: "Question",
other: "Something else",
} as const
type Topic = keyof typeof topics
// A feedback window: topic, subject, message, then a short thank-you.
export function Feedback01({
className,
...props
}: React.ComponentProps<typeof Window>) {
const subjectId = React.useId()
const messageId = React.useId()
const [topic, setTopic] = React.useState<Topic>("idea")
const [subject, setSubject] = React.useState("")
const [message, setMessage] = React.useState("")
const [sent, setSent] = React.useState(false)
return (
<Window className={cn("h-[440px] w-[400px]", className)} {...props}>
<WindowMain>
<WindowTitlebar>
<WindowControls />
<WindowTitle>Feedback</WindowTitle>
</WindowTitlebar>
<WindowContent className="flex flex-col px-5 py-4">
{sent ? (
<div className="flex flex-1 flex-col items-center justify-center text-center">
<IconTile color="green" className="size-16 rounded-[16px] [&_svg]:size-8">
<CheckIcon strokeWidth={2} />
</IconTile>
<h2 className="mt-4 text-mac-title-1 font-bold">Thanks for the note</h2>
<p className="mt-1 max-w-[260px] text-mac-body text-mac-label-secondary">
{`${subject ? `${topics[topic]}: ${subject}` : topics[topic]}. This is a sample, so nothing was sent.`}
</p>
<Button
variant="secondary"
className="mt-6"
onClick={() => {
setSent(false)
setSubject("")
setMessage("")
}}
>
Send Another
</Button>
</div>
) : (
<form
className="flex flex-1 flex-col gap-3"
onSubmit={(event) => {
event.preventDefault()
setSent(true)
}}
>
<div className="flex items-center justify-between gap-3">
<Label>Topic</Label>
<Select
value={topic}
onValueChange={(value) => value && setTopic(value as Topic)}
items={topics}
>
<SelectTrigger aria-label="Topic">
<SelectValue />
</SelectTrigger>
<SelectContent>
{(Object.keys(topics) as Topic[]).map((value) => (
<SelectItem key={value} value={value}>
{topics[value]}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div className="flex flex-col gap-1">
<Label htmlFor={subjectId}>Subject</Label>
<Input
id={subjectId}
value={subject}
onChange={(event) => setSubject(event.target.value)}
placeholder="A short summary"
/>
</div>
<div className="flex min-h-0 flex-1 flex-col gap-1">
<Label htmlFor={messageId}>Message</Label>
<Textarea
id={messageId}
value={message}
onChange={(event) => setMessage(event.target.value)}
placeholder="What happened, or what would help?"
className="min-h-24 flex-1 resize-none"
required
/>
</div>
<Label className="gap-[6px]">
<Checkbox />
Include a screenshot
</Label>
<div className="flex justify-end">
<Button type="submit" disabled={!message.trim()}>
Send
</Button>
</div>
</form>
)}
</WindowContent>
</WindowMain>
</Window>
)
}