feat: replace inputs with textareas in admin form and add URL auto-linking support for form labels and options
This commit is contained in:
@@ -286,11 +286,11 @@ export default function FormEditorClient({ form, initialQuestions }: FormEditorC
|
||||
<CardContent className="pt-6 space-y-4">
|
||||
<div className="flex flex-col sm:flex-row items-start sm:items-center gap-4">
|
||||
<div className="flex-1 w-full">
|
||||
<Input
|
||||
<Textarea
|
||||
value={q.label}
|
||||
onChange={(e) => handleUpdateQuestion(q.id, { label: e.target.value })}
|
||||
placeholder="Question Text"
|
||||
className="font-medium text-base w-full"
|
||||
className="font-medium text-base w-full min-h-10 py-2"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 self-end sm:self-auto">
|
||||
@@ -384,10 +384,10 @@ export default function FormEditorClient({ form, initialQuestions }: FormEditorC
|
||||
{(q.options || []).map((opt, optIdx) => (
|
||||
<div key={optIdx} className="flex items-center gap-2">
|
||||
<span className="w-2 h-2 rounded-full bg-muted-foreground" />
|
||||
<Input
|
||||
<Textarea
|
||||
value={opt}
|
||||
onChange={(e) => handleUpdateOption(q, optIdx, e.target.value)}
|
||||
className="h-8 max-w-sm"
|
||||
className="min-h-10 max-w-sm py-2"
|
||||
/>
|
||||
<Button
|
||||
variant="ghost"
|
||||
|
||||
+38
-3
@@ -28,6 +28,41 @@ import {
|
||||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
|
||||
function FormattedText({ text }: { text: string }) {
|
||||
const lines = text.split('\n');
|
||||
const urlRegex = /(https?:\/\/[^\s]+)/g;
|
||||
|
||||
return (
|
||||
<>
|
||||
{lines.map((line, i) => {
|
||||
const parts = line.split(urlRegex);
|
||||
return (
|
||||
<React.Fragment key={i}>
|
||||
{i > 0 && <br />}
|
||||
{parts.map((part, j) => {
|
||||
if (part.match(urlRegex)) {
|
||||
return (
|
||||
<a
|
||||
key={j}
|
||||
href={part}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-primary hover:underline underline-offset-4"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
{part}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
return part;
|
||||
})}
|
||||
</React.Fragment>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export function FormLayoutClient({
|
||||
userName,
|
||||
userImage,
|
||||
@@ -275,7 +310,7 @@ export function FormFillerClient({ form, questions, initialAnswers = {} }: FormF
|
||||
<CardHeader className="pb-3">
|
||||
<div className="flex items-start justify-between gap-4">
|
||||
<Label className="text-base font-semibold leading-normal mt-1">
|
||||
{q.label}
|
||||
<FormattedText text={q.label} />
|
||||
{q.required && <span className="text-destructive ml-1">*</span>}
|
||||
</Label>
|
||||
{q.imageUrl && (
|
||||
@@ -351,7 +386,7 @@ export function FormFillerClient({ form, questions, initialAnswers = {} }: FormF
|
||||
<div key={idx} className="flex items-center space-x-2">
|
||||
<RadioGroupItem value={opt} id={`${q.id}-${idx}`} />
|
||||
<Label htmlFor={`${q.id}-${idx}`} className="font-normal cursor-pointer">
|
||||
{opt}
|
||||
<FormattedText text={opt} />
|
||||
</Label>
|
||||
</div>
|
||||
))}
|
||||
@@ -398,7 +433,7 @@ export function FormFillerClient({ form, questions, initialAnswers = {} }: FormF
|
||||
}}
|
||||
/>
|
||||
<Label htmlFor={`${q.id}-${idx}`} className="font-normal cursor-pointer">
|
||||
{opt}
|
||||
<FormattedText text={opt} />
|
||||
</Label>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user