← back to Letsbegin

components/ProjectSelector.tsx

124 lines

'use client'

import { useState, useRef, useEffect } from 'react'

interface Project {
  name: string
  path: string
  hasClaudeMd: boolean
}

interface Props {
  projects: Project[]
  selectedProject: Project | null
  onSelect: (project: Project) => void
  onCreateNew: () => void
}

export default function ProjectSelector({ projects, selectedProject, onSelect, onCreateNew }: Props) {
  const [isOpen, setIsOpen] = useState(false)
  const [search, setSearch] = useState('')
  const dropdownRef = useRef<HTMLDivElement>(null)

  useEffect(() => {
    function handleClickOutside(event: MouseEvent) {
      if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
        setIsOpen(false)
      }
    }
    document.addEventListener('mousedown', handleClickOutside)
    return () => document.removeEventListener('mousedown', handleClickOutside)
  }, [])

  const filteredProjects = projects.filter(p =>
    p.name.toLowerCase().includes(search.toLowerCase())
  )

  return (
    <div className="relative" ref={dropdownRef}>
      <button
        onClick={() => setIsOpen(!isOpen)}
        className="flex items-center gap-2 px-4 py-2 rounded-lg bg-[var(--surface-alt)] border border-[var(--border)] hover:border-[var(--primary)] transition-colors min-w-[200px]"
      >
        <span className="text-[var(--foreground-secondary)]">Project:</span>
        <span className="font-medium truncate max-w-[150px]">
          {selectedProject?.name || 'Select...'}
        </span>
        <svg
          className={`w-4 h-4 text-[var(--foreground-secondary)] transition-transform ${isOpen ? 'rotate-180' : ''}`}
          fill="none"
          stroke="currentColor"
          viewBox="0 0 24 24"
        >
          <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
        </svg>
      </button>

      {isOpen && (
        <div className="absolute top-full mt-2 right-0 w-80 bg-[var(--surface)] border border-[var(--border)] rounded-xl shadow-lg overflow-hidden z-50">
          {/* Search */}
          <div className="p-3 border-b border-[var(--border)]">
            <input
              type="text"
              placeholder="Search projects..."
              value={search}
              onChange={(e) => setSearch(e.target.value)}
              className="input text-sm"
              autoFocus
            />
          </div>

          {/* Project List */}
          <div className="max-h-64 overflow-y-auto">
            {filteredProjects.map((project) => (
              <button
                key={project.path}
                onClick={() => {
                  onSelect(project)
                  setIsOpen(false)
                  setSearch('')
                }}
                className={`w-full flex items-center gap-3 px-4 py-3 hover:bg-[var(--surface-alt)] transition-colors ${
                  selectedProject?.path === project.path ? 'bg-[var(--surface-alt)]' : ''
                }`}
              >
                <span className="text-lg">📁</span>
                <div className="flex-1 text-left">
                  <div className="font-medium">{project.name}</div>
                  <div className="text-xs text-[var(--foreground-tertiary)] truncate">
                    {project.path}
                  </div>
                </div>
                {project.hasClaudeMd && (
                  <span className="badge badge-success text-xs">CLAUDE.md</span>
                )}
              </button>
            ))}
            {filteredProjects.length === 0 && (
              <div className="px-4 py-6 text-center text-[var(--foreground-tertiary)]">
                No projects found
              </div>
            )}
          </div>

          {/* Create New */}
          <div className="border-t border-[var(--border)] p-3">
            <button
              onClick={() => {
                onCreateNew()
                setIsOpen(false)
              }}
              className="w-full flex items-center justify-center gap-2 px-4 py-2 rounded-lg bg-[var(--primary)] text-white font-medium hover:bg-[var(--primary-dark)] transition-colors"
            >
              <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 4v16m8-8H4" />
              </svg>
              Create New Project
            </button>
          </div>
        </div>
      )}
    </div>
  )
}