funes-memory 1.0.0

Your machine's memory, queryable. Local AI memory for the terminal.
"use client";

import { Check } from "lucide-react";

type RoadmapItem = {
  label: string;
  done: boolean;
  detail?: string;
};

const ROADMAP: RoadmapItem[] = [
  { label: "CLI skeleton", done: true, detail: "basic command structure" },
  { label: "Ollama embeddings working", done: true, detail: "local model integration" },
  { label: "SQLite / vector storage", done: true, detail: "persistent local index" },
  { label: "File watcher", done: false, detail: "live indexing on change" },
  { label: "Shell history indexing", done: false, detail: "bash / zsh / fish support" },
  { label: "Query with results", done: false, detail: "semantic search over index" },
  { label: "LLM synthesis mode", done: false, detail: "plain English answers" },
  { label: "Packaging (Homebrew, Cargo)", done: false, detail: "one-line install" },
];

export default function Roadmap() {
  const completedCount = ROADMAP.filter((item) => item.done).length;
  const progress = (completedCount / ROADMAP.length) * 100;

  return (
    <section id="roadmap" className="px-6 pt-18">
      <div className="w-full max-w-2xl mx-auto space-y-10">

        {/* Header */}
        <div className="space-y-2">
          <p className="text-sm text-[hsl(var(--muted-foreground))]">
            — roadmap
          </p>
          <div className="flex items-baseline justify-between">
            <h2 className="text-3xl font-bold tracking-tight">status</h2>
            <span className="text-sm text-[hsl(var(--muted-foreground))]">
              {completedCount}/{ROADMAP.length} done
            </span>
          </div>
        </div>

        <p className="text-[hsl(var(--muted-foreground))] leading-relaxed">
          funes is early and under active development. things will break.
          contributions are very welcome.
        </p>

        {/* Progress bar */}
        <div className="space-y-2">
          <div className="h-2 w-full rounded-full bg-[hsl(var(--muted))] overflow-hidden">
            <div
              className="h-full rounded-full bg-[hsl(var(--foreground))] transition-all duration-700 ease-out"
              style={{ width: `${progress}%` }}
            />
          </div>
          <p className="text-xs text-[hsl(var(--muted-foreground))]">
            {Math.round(progress)}% complete
          </p>
        </div>

        {/* Timeline */}
        <div className="relative pl-1">
          {/* connecting line */}
          <div className="absolute left-3 top-2 bottom-0 w-px bg-[hsl(var(--border))]" />
          {/* filled portion of the line, up to last completed item */}
          <div
            className="absolute left-3 top-4 w-px bg-[hsl(var(--foreground))] transition-all duration-700 ease-out"
            style={{
              height:
                completedCount === 0
                  ? "0%"
                  : `calc(${((completedCount - 1) / (ROADMAP.length - 1)) * 100}% + 2px)`,
            }}
          />

          <div className="space-y-6">
            {ROADMAP.map((item) => (
              <div key={item.label} className="relative flex gap-4 pl-0">
                <span
                  className={`relative z-10 flex h-[18px] w-[18px] shrink-0 items-center justify-center rounded-full border-2 transition-colors ${
                    item.done
                      ? "bg-[hsl(var(--foreground))] border-[hsl(var(--foreground))]"
                      : "bg-[hsl(var(--background))] border-[hsl(var(--border))]"
                  }`}
                >
                  {item.done && (
                    <Check
                      size={10}
                      strokeWidth={3}
                      className="text-[hsl(var(--background))]"
                    />
                  )}
                </span>

                <div className="flex-1 -translate-y-0.5">
                  <p
                    className={`text-sm ${
                      item.done
                        ? "text-[hsl(var(--muted-foreground))] line-through decoration-[hsl(var(--muted-foreground))]"
                        : "text-[hsl(var(--foreground))]"
                    }`}
                  >
                    {item.label}
                  </p>
                  {item.detail && (
                    <p className="text-xs text-[hsl(var(--muted-foreground))] mt-0.5">
                      {item.detail}
                    </p>
                  )}
                </div>
              </div>
            ))}
          </div>
        </div>

        <p className="text-xs text-[hsl(var(--muted-foreground))]">
          want to help build one of these? see{" "}
          <a
            href="https://github.com/bhavv04/funes/blob/main/CONTRIBUTING.md"
            target="_blank"
            rel="noopener noreferrer"
            className="underline underline-offset-4 hover:text-[hsl(var(--foreground))] transition-colors"
          >
            CONTRIBUTING.md
          </a>
          .
        </p>
      </div>
    </section>
  );
}