aboutsummaryrefslogtreecommitdiffstats
path: root/renderer/src/components/Header.tsx
blob: 84b913574f5ddeb53304470da2b8451256a61b07 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
import React, { useState, useEffect } from "react";
import type { Session, Phase } from "../types";

const api = window.api;

interface HeaderProps {
  selectedSession: Session | null;
  gitBranch: string | null;
  onOpenSettings: () => void;
  viewPhase: Phase;
  onViewPhase: (phase: Phase) => void;
}

const phaseLabels: Record<Phase, string> = {
  research: "Research",
  plan: "Plan",
  implement: "Implement",
};

const phases: Phase[] = ["research", "plan", "implement"];

export function Header({
  selectedSession,
  gitBranch,
  onOpenSettings,
  viewPhase,
  onViewPhase,
}: HeaderProps) {
  // ── Maximize ─────────────────────────────────────────────────
  const [isMaximized, setIsMaximized] = useState(false);

  useEffect(() => {
    return api.onWindowMaximized(setIsMaximized);
  }, []);

  // ── Branch copy ──────────────────────────────────────────────
  const [copied, setCopied] = useState(false);

  const handleCopyBranch = () => {
    if (!gitBranch) return;
    navigator.clipboard.writeText(gitBranch);
    setCopied(true);
    setTimeout(() => setCopied(false), 1500);
  };

  return (
    <header className="header">
      <div className="header-left">
        <span className="app-wordmark">Claude Flow</span>
      </div>

      <div className="header-right">
        {selectedSession && (
          <div className="phase-indicator">
            {phases.map((phase) => {
              const phaseIndex = phases.indexOf(phase);
              const currentIndex = phases.indexOf(selectedSession.phase);
              const isComplete = phaseIndex < currentIndex;
              const isActive = phase === selectedSession.phase;
              const isReachable = phaseIndex <= currentIndex;
              const isViewing = phase === viewPhase && !isActive;

              return isReachable ? (
                <button
                  key={phase}
                  className={`phase-step ${isActive ? "active" : ""} ${
                    isComplete ? "complete" : ""
                  } ${isViewing ? "viewing" : ""}`}
                  onClick={() => onViewPhase(phase)}
                  title={
                    isActive
                      ? `Viewing ${phaseLabels[phase]} (current)`
                      : `View ${phaseLabels[phase]} artifact`
                  }
                >
                  {phaseLabels[phase]}
                </button>
              ) : (
                <span key={phase} className="phase-step">
                  {phaseLabels[phase]}
                </span>
              );
            })}
          </div>
        )}

        {/* ── Branch badge ── */}
        {selectedSession && gitBranch && (
          <button
            className={["branch-badge", copied ? "branch-copied" : ""]
              .filter(Boolean)
              .join(" ")}
            onClick={handleCopyBranch}
            title={copied ? "Copied!" : `Click to copy: ${gitBranch}`}
          >{gitBranch}
          </button>
        )}

        {/* ── Maximize toggle ── */}
        <button
          className="maximize-btn"
          onClick={() => api.toggleMaximize()}
          title={isMaximized ? "Restore window" : "Maximize window"}
        >
          {isMaximized ? "⊡" : "□"}
        </button>

        {/* ── Settings button ── */}
        <button className="settings-btn" onClick={onOpenSettings} title="Settings">
          &#9881;
        </button>
      </div>
    </header>
  );
}