diff --git a/src/components/FocusView.tsx b/src/components/FocusView.tsx
index 5bd01c9..10cff76 100644
--- a/src/components/FocusView.tsx
+++ b/src/components/FocusView.tsx
@@ -3,10 +3,16 @@
*
* Connects to the Zustand store and Tauri backend.
* Handles "Start" by opening the URL in the browser via Tauri shell.
+ *
+ * Focus selection logic:
+ * 1. If user has set a focus (current) -> show FocusCard with that item
+ * 2. If no focus set but queue has items -> show suggestion from queue
+ * 3. If no focus and no items -> show empty/celebration state
*/
import { useCallback } from "react";
import { FocusCard } from "./FocusCard";
+import { SuggestionCard } from "./SuggestionCard";
import { QueueSummary } from "./QueueSummary";
import { useFocusStore } from "@/stores/focus-store";
import { open } from "@tauri-apps/plugin-shell";
@@ -17,6 +23,15 @@ export function FocusView(): React.ReactElement {
const isLoading = useFocusStore((s) => s.isLoading);
const error = useFocusStore((s) => s.error);
const act = useFocusStore((s) => s.act);
+ const setFocus = useFocusStore((s) => s.setFocus);
+
+ // The suggestion is the first item in the queue when no focus is set
+ const suggestion = !current && queue.length > 0 ? queue[0] : null;
+
+ // Determine what to show in the queue summary:
+ // - If we have a suggestion, show remaining queue (minus the suggestion)
+ // - Otherwise, show full queue
+ const displayQueue = suggestion ? queue.slice(1) : queue;
const handleStart = useCallback(() => {
if (current?.url) {
@@ -39,6 +54,13 @@ export function FocusView(): React.ReactElement {
act("skip");
}, [act]);
+ // Handle setting suggestion as focus
+ const handleSetAsFocus = useCallback(() => {
+ if (suggestion) {
+ setFocus(suggestion.id);
+ }
+ }, [suggestion, setFocus]);
+
if (isLoading) {
return (
@@ -59,17 +81,26 @@ export function FocusView(): React.ReactElement {
{/* Main focus area */}
-
+ {suggestion ? (
+ // Suggestion state: no focus set, but items exist
+
+ ) : (
+ // Focus state or empty state (FocusCard handles empty internally)
+
+ )}
{/* Queue summary bar */}
-
+
);
}
diff --git a/src/components/SuggestionCard.tsx b/src/components/SuggestionCard.tsx
new file mode 100644
index 0000000..1236763
--- /dev/null
+++ b/src/components/SuggestionCard.tsx
@@ -0,0 +1,98 @@
+/**
+ * SuggestionCard -- displays a suggested next item when no focus is set.
+ *
+ * Shows the item with a "Set as focus" button to promote it to THE ONE THING.
+ * This is used when the queue has items but the user hasn't picked one yet.
+ */
+
+import { motion } from "framer-motion";
+import type { FocusItem, FocusItemType, Staleness } from "@/lib/types";
+import { computeStaleness } from "@/lib/types";
+import { formatIid } from "@/lib/format";
+
+interface SuggestionCardProps {
+ item: FocusItem;
+ onSetAsFocus: () => void;
+}
+
+const TYPE_LABELS: Record = {
+ mr_review: "MR REVIEW",
+ issue: "ISSUE",
+ mr_authored: "MR AUTHORED",
+ manual: "TASK",
+};
+
+const STALENESS_COLORS: Record = {
+ fresh: "bg-mc-fresh/20 text-mc-fresh border-mc-fresh/30",
+ normal: "bg-zinc-700/50 text-zinc-300 border-zinc-600",
+ amber: "bg-mc-amber/20 text-mc-amber border-mc-amber/30",
+ urgent: "bg-mc-urgent/20 text-mc-urgent border-mc-urgent/30",
+};
+
+export function SuggestionCard({
+ item,
+ onSetAsFocus,
+}: SuggestionCardProps): React.ReactElement {
+ const staleness = computeStaleness(item.updatedAt);
+
+ return (
+
+ {/* Suggestion label */}
+
Suggested next
+
+ {/* Type badge */}
+
+
+ {TYPE_LABELS[item.type]}
+
+
+
+ {/* Title */}
+
+ {item.title}
+
+
+ {/* Metadata line */}
+
+ {formatIid(item.type, item.iid)} in {item.project}
+