code-graph-cli 3.0.3

Code intelligence engine for TypeScript/JavaScript/Rust/Python/Go — query the dependency graph instead of reading source files.
<script lang="ts">
  interface Props {
    onSend: (text: string) => void;
    isThinking?: boolean;
    disabled?: boolean;
  }

  let { onSend, isThinking = false, disabled = false }: Props = $props();

  let inputText = $state('');
  let textareaEl: HTMLTextAreaElement | null = $state(null);

  function handleKeydown(e: KeyboardEvent) {
    if (e.key === 'Enter' && !e.shiftKey) {
      e.preventDefault();
      submit();
    }
  }

  function submit() {
    const text = inputText.trim();
    if (!text || isThinking || disabled) return;
    onSend(text);
    inputText = '';
    // Reset textarea height after send
    if (textareaEl) {
      textareaEl.style.height = 'auto';
    }
  }

  function handleInput() {
    if (!textareaEl) return;
    // Auto-resize: reset to auto first, then set scrollHeight
    textareaEl.style.height = 'auto';
    textareaEl.style.height = Math.min(textareaEl.scrollHeight, 160) + 'px';
  }
</script>

<div class="chat-input-bar">
  <textarea
    bind:this={textareaEl}
    bind:value={inputText}
    onkeydown={handleKeydown}
    oninput={handleInput}
    disabled={isThinking || disabled}
    placeholder={disabled ? 'Configure a provider to start chatting...' : 'Ask about your codebase...'}
    rows="1"
    class="chat-textarea"
  ></textarea>
  <button
    class="send-btn"
    onclick={submit}
    disabled={isThinking || disabled || !inputText.trim()}
    title="Send message"
    aria-label="Send message"
  >
    <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
      <line x1="22" y1="2" x2="11" y2="13"/>
      <polygon points="22 2 15 22 11 13 2 9 22 2"/>
    </svg>
  </button>
</div>

<style>
  .chat-input-bar {
    display: flex;
    align-items: flex-end;
    gap: 8px;
    padding: 10px 12px;
    border-top: 1px solid var(--color-border);
    background: var(--color-bg-secondary);
    flex-shrink: 0;
  }

  .chat-textarea {
    flex: 1;
    resize: none;
    background: var(--color-bg-elevated);
    border: 1px solid var(--color-border);
    border-radius: 8px;
    color: var(--color-text-primary);
    font-size: 13px;
    font-family: inherit;
    line-height: 1.5;
    padding: 8px 10px;
    outline: none;
    min-height: 36px;
    max-height: 160px;
    overflow-y: auto;
    transition: border-color 150ms ease;
  }

  .chat-textarea::placeholder {
    color: var(--color-text-muted);
  }

  .chat-textarea:focus {
    border-color: var(--color-accent, #7c5cfc);
  }

  .chat-textarea:disabled {
    opacity: 0.5;
    cursor: not-allowed;
  }

  .send-btn {
    width: 36px;
    height: 36px;
    flex-shrink: 0;
    border-radius: 8px;
    border: none;
    background: var(--color-accent, #7c5cfc);
    color: white;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: opacity 150ms ease, background 150ms ease;
  }

  .send-btn:hover:not(:disabled) {
    opacity: 0.85;
  }

  .send-btn:disabled {
    opacity: 0.35;
    cursor: not-allowed;
  }
</style>