diff --git a/vibes.diy/pkg/app/components/QuickSuggestions.tsx b/vibes.diy/pkg/app/components/QuickSuggestions.tsx index 1af04c157..9ccb7a7f4 100644 --- a/vibes.diy/pkg/app/components/QuickSuggestions.tsx +++ b/vibes.diy/pkg/app/components/QuickSuggestions.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from "react"; +import React, { useEffect, useMemo, useState } from "react"; import { quickSuggestions } from "../data/quick-suggestions-data.js"; interface QuickSuggestionsProps { @@ -12,6 +12,24 @@ interface Suggestion { function QuickSuggestions({ onSelectSuggestion }: QuickSuggestionsProps) { const [randomSuggestions, setRandomSuggestions] = useState([]); + const [selected, setSelected] = useState>(new Set()); + + const allSelected = useMemo( + () => + randomSuggestions.length > 0 && + selected.size === randomSuggestions.length, + [randomSuggestions.length, selected.size], + ); + + const buildCombinedPrompt = (indexes: Set) => { + const items = Array.from(indexes) + .sort((a, b) => a - b) + .map((i) => randomSuggestions[i]) + .filter(Boolean); + if (items.length === 0) return ""; + // Join selected feature prompts in a concise, model-friendly way + return items.map((s) => `- ${s.label}: ${s.text}`).join("\n"); + }; useEffect(() => { const shuffled = [...quickSuggestions].sort(() => 0.5 - Math.random()); @@ -23,17 +41,74 @@ function QuickSuggestions({ onSelectSuggestion }: QuickSuggestionsProps) {

Create custom vibes from a prompt

-
- {randomSuggestions.map((suggestion, index) => ( - - ))} + {/* Selection toolbar */} + {randomSuggestions.length > 0 && ( +
+ + {selected.size > 0 && ( + + )} +
+ )} + + {/* Suggestions list: checkbox for multi-select + pill button for single insert */} +
+ {randomSuggestions.map((suggestion, index) => { + const isChecked = selected.has(index); + return ( +
+ { + const next = new Set(selected); + if (e.currentTarget.checked) next.add(index); + else next.delete(index); + setSelected(next); + const combined = buildCombinedPrompt(next); + if (combined) onSelectSuggestion(combined); + }} + className="h-4 w-4 accent-blue-600" + /> + +
+ ); + })}
); diff --git a/vibes.diy/tests/app/QuickSuggestions.test.tsx b/vibes.diy/tests/app/QuickSuggestions.test.tsx index 619947765..520e62ca8 100644 --- a/vibes.diy/tests/app/QuickSuggestions.test.tsx +++ b/vibes.diy/tests/app/QuickSuggestions.test.tsx @@ -74,3 +74,27 @@ describe("QuickSuggestions", () => { expect(button).toHaveClass("cursor-pointer"); }); }); + + it("supports select-all checkbox to auto-fill combined features", () => { + const onSelectSuggestion = vi.fn(); + const { container } = render( + , + ); + + const selectAll = container.querySelector( + 'input[aria-label="Select all suggested features"]', + ) as HTMLInputElement | null; + expect(selectAll).not.toBeNull(); + + if (selectAll) { + // Click the select-all checkbox + fireEvent.click(selectAll); + + // Verify callback was invoked with a combined string + expect(onSelectSuggestion).toHaveBeenCalled(); + const arg = onSelectSuggestion.mock.calls[0][0]; + expect(typeof arg).toBe("string"); + // Combined prompt should contain multiple lines joined with dashes + expect(arg.includes("- ")).toBe(true); + } + });