intent-engine 0.11.1

A command-line database service for tracking strategic intent, tasks, and events
Documentation
<script setup lang="ts">
import { computed } from 'vue'
import { useAppStore } from '../stores/appStore'
import { Target, Play, Square } from 'lucide-vue-next'

interface TaskNode {
  id: number
  name: string
  status: string
  children?: TaskNode[]
  isOpen?: boolean
  [key: string]: any
}

const props = defineProps<{
  node: TaskNode
  depth?: number
  forceOpen?: boolean
}>()

const store = useAppStore()
const depth = props.depth || 0
const paddingLeft = computed(() => `${depth * 12 + 8}px`)

const isActive = computed(() => store.viewingTaskId === props.node.id)

function selectTask() {
  store.viewingTaskId = props.node.id
  store.fetchTaskDetail(props.node.id)
}

const activeClass = computed(() => {
  if (!isActive.value) {
    return 'border-transparent hover:bg-sci-panel-hover hover:text-sci-text-pri'
  }
  
  switch (props.node.priority) {
    case 1: return 'bg-sci-danger-dim border-sci-danger text-sci-danger'
    case 2: return 'bg-sci-orange-dim border-sci-orange text-sci-orange'
    case 3: return 'bg-sci-cyan-dim border-sci-cyan text-sci-cyan'
    default: return 'bg-sci-panel-hover border-sci-text-dim text-sci-text-pri'
  }
})
</script>

<template>
  <div class="select-none relative">
    <!-- Connecting Line (Vertical) -->
    <div v-if="depth > 0" class="absolute left-0 top-0 bottom-0 w-px bg-sci-border opacity-30" :style="{ left: `${(depth * 12) - 6}px` }"></div>

    <div 
      class="group flex items-center gap-2 py-1.5 px-2 cursor-pointer transition-all border-l-2 relative overflow-hidden"
      :class="activeClass"
      :style="{ paddingLeft }"
      @click="selectTask"
    >


      <!-- Status Indicator -->
      <div class="relative flex items-center justify-center w-5 h-5">
        <Play v-if="props.node.status === 'doing'" class="w-[18px] h-[18px] text-sci-text-dim" />
        
        <div v-else-if="props.node.status === 'done'" class="relative w-[18px] h-[18px]">
          <Square class="w-full h-full text-sci-text-dim" />
          <span class="absolute -top-[2px] right-0 flex items-center justify-center text-sci-text-dim font-serif font-bold text-lg leading-none select-none">✓</span>
        </div>
        
        <Square v-else class="w-[18px] h-[18px] text-sci-text-dim" />
      </div>
      
      <!-- Task ID -->
      <span class="text-[10px] font-mono text-sci-text-dim opacity-60 shrink-0">
        #{{ props.node.id }}
      </span>

      <span
        class="text-xs font-mono truncate flex-1 z-10 transition-colors"
        :class="[
          props.node.priority === 1 ? 'text-sci-danger' : '',
          props.node.priority === 2 ? 'text-sci-orange' : '',
          props.node.priority === 3 ? 'text-sci-cyan' : '',
          isActive && (!props.node.priority || props.node.priority > 3) ? 'text-sci-text-pri' : '',
          !isActive && (!props.node.priority || props.node.priority > 3) ? 'text-sci-text-sec' : ''
        ]"
      >
        {{ props.node.name }}
      </span>
      
      <!-- Current Focus Indicator -->
      <Target v-if="store.currentTaskId === props.node.id" class="w-[18px] h-[18px] text-sci-orange animate-pulse" />
    </div>
    
    <div v-if="props.node.children?.length" class="relative">
      <TaskTreeItem 
        v-for="child in props.node.children" 
        :key="child.id" 
        :node="child" 
        :depth="depth + 1" 
        :force-open="forceOpen"
      />
    </div>
  </div>
</template>