From 9e9f18884c78c21f5785908fb7ccd00e2fa5436b Mon Sep 17 00:00:00 2001
From: soryu <soryu@soryu.co>
Date: Sat, 7 Feb 2026 01:11:26 +0000
Subject: Add new directive initial implementation

---
 .../src/components/directives/DirectiveList.tsx    | 135 +++++++++++++++++++++
 1 file changed, 135 insertions(+)
 create mode 100644 makima/frontend/src/components/directives/DirectiveList.tsx

(limited to 'makima/frontend/src/components/directives/DirectiveList.tsx')

diff --git a/makima/frontend/src/components/directives/DirectiveList.tsx b/makima/frontend/src/components/directives/DirectiveList.tsx
new file mode 100644
index 0000000..a900b7b
--- /dev/null
+++ b/makima/frontend/src/components/directives/DirectiveList.tsx
@@ -0,0 +1,135 @@
+import { useState } from "react";
+import type { DirectiveSummary, DirectiveStatus } from "../../lib/api";
+
+interface DirectiveListProps {
+  directives: DirectiveSummary[];
+  loading: boolean;
+  onSelect: (id: string) => void;
+  onCreate: () => void;
+  onDelete?: (directive: DirectiveSummary) => void;
+  selectedId?: string;
+}
+
+const statusColors: Record<DirectiveStatus, string> = {
+  draft: "text-[#888]",
+  planning: "text-yellow-400",
+  active: "text-green-400",
+  paused: "text-orange-400",
+  completed: "text-blue-400",
+  archived: "text-[#555]",
+  failed: "text-red-400",
+};
+
+export function DirectiveList({
+  directives,
+  loading,
+  onSelect,
+  onCreate,
+  onDelete,
+  selectedId,
+}: DirectiveListProps) {
+  const [filter, setFilter] = useState<DirectiveStatus | "all">("all");
+
+  const filteredDirectives =
+    filter === "all"
+      ? directives
+      : directives.filter((d) => d.status === filter);
+
+  if (loading) {
+    return (
+      <div className="panel h-full flex items-center justify-center">
+        <div className="font-mono text-[#9bc3ff] text-sm">Loading...</div>
+      </div>
+    );
+  }
+
+  return (
+    <div className="panel h-full flex flex-col">
+      {/* Header */}
+      <div className="p-4 border-b border-dashed border-[rgba(117,170,252,0.35)]">
+        <div className="flex items-center justify-between mb-3">
+          <h2 className="font-mono text-sm text-[#75aafc] uppercase tracking-wider">
+            Directives
+          </h2>
+          <button
+            onClick={onCreate}
+            className="px-3 py-1.5 font-mono text-xs text-[#dbe7ff] bg-[#0f3c78] border border-[#3f6fb3] hover:bg-[#153667] transition-colors uppercase"
+          >
+            + New
+          </button>
+        </div>
+        {/* Filter tabs */}
+        <div className="flex gap-1 flex-wrap">
+          {(["all", "draft", "planning", "active", "paused", "completed", "failed"] as const).map(
+            (status) => (
+              <button
+                key={status}
+                onClick={() => setFilter(status)}
+                className={`px-2 py-0.5 font-mono text-[10px] uppercase tracking-wider border transition-colors ${
+                  filter === status
+                    ? "bg-[#0f3c78] border-[#3f6fb3] text-[#dbe7ff]"
+                    : "bg-transparent border-[rgba(117,170,252,0.2)] text-[#7788aa] hover:border-[rgba(117,170,252,0.4)]"
+                }`}
+              >
+                {status}
+              </button>
+            )
+          )}
+        </div>
+      </div>
+
+      {/* List */}
+      <div className="flex-1 overflow-y-auto">
+        {filteredDirectives.length === 0 ? (
+          <div className="p-4 text-center">
+            <p className="font-mono text-sm text-[#7788aa]">
+              {directives.length === 0
+                ? "No directives yet"
+                : "No matching directives"}
+            </p>
+          </div>
+        ) : (
+          filteredDirectives.map((directive) => (
+            <div
+              key={directive.id}
+              onClick={() => onSelect(directive.id)}
+              onContextMenu={(e) => {
+                if (onDelete) {
+                  e.preventDefault();
+                }
+              }}
+              className={`p-3 border-b border-dashed border-[rgba(117,170,252,0.15)] cursor-pointer transition-colors hover:bg-[rgba(117,170,252,0.05)] ${
+                selectedId === directive.id
+                  ? "bg-[rgba(117,170,252,0.1)]"
+                  : ""
+              }`}
+            >
+              <div className="flex items-start justify-between gap-2">
+                <div className="flex-1 min-w-0">
+                  <div className="font-mono text-sm text-[#dbe7ff] truncate">
+                    {directive.title}
+                  </div>
+                  <div className="font-mono text-xs text-[#7788aa] mt-0.5 line-clamp-2">
+                    {directive.goal}
+                  </div>
+                </div>
+                <div className="flex flex-col items-end gap-1 shrink-0">
+                  <span
+                    className={`font-mono text-[10px] uppercase ${
+                      statusColors[directive.status] || "text-[#888]"
+                    }`}
+                  >
+                    {directive.status}
+                  </span>
+                  <span className="font-mono text-[10px] text-[#7788aa]">
+                    {directive.chainCount}ch / {directive.stepCount}st
+                  </span>
+                </div>
+              </div>
+            </div>
+          ))
+        )}
+      </div>
+    </div>
+  );
+}
-- 
cgit v1.2.3

