# vue_components

id: simple-card
name: SimpleCard
setup: const count = ref(0) return { count }
props: []
imports: ["ref"]
created_at: 2026-02-13 10:22:26
updated_at: 2026-02-13 10:22:26
template:
<div class="card">
  <h3>Hola!</h3>
  <p>Clicks: {{ count }}</p>
  <button @click="count++">Click</button>
</div>

style:
.card {
  max-width: 200px;
  margin: 2rem auto;
  padding: 1.5rem;
  background: #2d2d44;
  border-radius: 12px;
  text-align: center;
  color: white;
}
button {
  margin-top: 1rem;
  padding: 0.5rem 1.5rem;
  background: #6366f1;
  border: none;
  border-radius: 6px;
  color: white;
  cursor: pointer;
}
button:hover {
  background: #4f46e5;
}


id: debug-panel
name: DebugPanel
props: []
imports: ["ref","reactive","onMounted"]
created_at: 2026-02-13 10:33:18
updated_at: 2026-02-13 10:33:18
template:
<div class="debug-panel" :class="{ minimized }">
  <div class="debug-header" @click="minimized = !minimized">
    <div class="debug-title">
      <span class="pulse"></span>
      DEBUG
    </div>
    <div class="debug-controls">
      <span class="tab" :class="{ active: tab === 'state' }" @click.stop="tab = 'state'">State</span>
      <span class="tab" :class="{ active: tab === 'events' }" @click.stop="tab = 'events'">Events</span>
      <span class="tab" :class="{ active: tab === 'console' }" @click.stop="tab = 'console'">Console</span>
    </div>
  </div>
  
  <div class="debug-body" v-show="!minimized">
    <!-- State Tab -->
    <div v-if="tab === 'state'" class="tab-content">
      <div class="state-item" v-for="(value, key) in state" :key="key">
        <span class="key">{{ key }}</span>
        <span class="value" :class="typeof value">{{ formatValue(value) }}</span>
      </div>
      <button class="action-btn" @click="refreshState">Refresh</button>
    </div>
    
    <!-- Events Tab -->
    <div v-if="tab === 'events'" class="tab-content">
      <div class="event-item" v-for="(evt, i) in events" :key="i">
        <span class="event-time">{{ evt.time }}</span>
        <span class="event-name">{{ evt.name }}</span>
      </div>
      <div v-if="events.length === 0" class="empty">No events captured</div>
      <button class="action-btn danger" @click="events = []">Clear</button>
    </div>
    
    <!-- Console Tab -->
    <div v-if="tab === 'console'" class="tab-content">
      <div class="console-input">
        <span class="prompt">></span>
        <input v-model="cmd" @keyup.enter="execCmd" placeholder="eval()" />
      </div>
      <div class="console-output">
        <div v-for="(log, i) in logs" :key="i" class="log-item" :class="log.type">
          <span class="log-prefix">{{ log.type === 'error' ? '✗' : '→' }}</span>
          <span class="log-content">{{ log.content }}</span>
        </div>
      </div>
    </div>
  </div>
  
  <div class="debug-footer" v-show="!minimized">
    <span class="metric">
      <span class="metric-value">{{ fps }}</span> FPS
    </span>
    <span class="metric">
      <span class="metric-value">{{ memory }}</span> MB
    </span>
    <span class="metric">
      <span class="metric-value">{{ Date.now() - startTime }}</span> ms
    </span>
  </div>
</div>

setup:
const minimized = ref(false)
const tab = ref('state')
const cmd = ref('')
const logs = ref([])
const events = ref([])
const fps = ref(60)
const memory = ref(0)
const startTime = Date.now()

const state = reactive({
  connected: false,
  components: 0,
  lastRender: null,
  theme: 'dark',
  windowSize: `${window.innerWidth}x${window.innerHeight}`
})

function formatValue(val) {
  if (val === null) return 'null'
  if (val === undefined) return 'undefined'
  if (typeof val === 'object') return JSON.stringify(val)
  return String(val)
}

function refreshState() {
  state.windowSize = `${window.innerWidth}x${window.innerHeight}`
  state.lastRender = new Date().toLocaleTimeString()
  state.connected = window.webmcp?.isConnected || false
}

function execCmd() {
  if (!cmd.value.trim()) return
  try {
    const result = eval(cmd.value)
    logs.value.unshift({ type: 'result', content: formatValue(result) })
  } catch (e) {
    logs.value.unshift({ type: 'error', content: e.message })
  }
  cmd.value = ''
}

// Track events
const trackEvent = (name) => (e) => {
  events.value.unshift({ 
    name, 
    time: new Date().toLocaleTimeString() 
  })
  if (events.value.length > 20) events.value.pop()
}

// FPS counter
let frameCount = 0
let lastTime = performance.now()
const updateFPS = () => {
  frameCount++
  const now = performance.now()
  if (now - lastTime >= 1000) {
    fps.value = frameCount
    frameCount = 0
    lastTime = now
  }
  requestAnimationFrame(updateFPS)
}

// Memory
const updateMemory = () => {
  if (performance.memory) {
    memory.value = Math.round(performance.memory.usedJSHeapSize / 1048576)
  }
}

onMounted(() => {
  refreshState()
  updateFPS()
  setInterval(updateMemory, 2000)
  
  window.addEventListener('click', trackEvent('click'))
  window.addEventListener('keydown', trackEvent('keydown'))
  window.addEventListener('vue-component-rendered', trackEvent('component-rendered'))
})

return { 
  minimized, tab, cmd, logs, events, state, fps, memory, startTime,
  formatValue, refreshState, execCmd 
}

style:
.debug-panel {
  --neon: #0ff;
  --neon-pink: #f0f;
  --neon-green: #0f0;
  --bg: rgba(0, 0, 0, 0.85);
  
  position: fixed;
  bottom: 80px;
  right: 20px;
  width: 340px;
  background: var(--bg);
  border: 1px solid var(--neon);
  border-radius: 8px;
  font-family: 'JetBrains Mono', 'Fira Code', monospace;
  font-size: 12px;
  color: var(--neon);
  box-shadow: 
    0 0 20px rgba(0, 255, 255, 0.3),
    inset 0 0 20px rgba(0, 255, 255, 0.05);
  backdrop-filter: blur(10px);
  z-index: 9999;
  overflow: hidden;
}

.debug-panel.minimized {
  width: auto;
}

.debug-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 12px;
  background: linear-gradient(90deg, rgba(0,255,255,0.1) 0%, transparent 100%);
  border-bottom: 1px solid rgba(0, 255, 255, 0.3);
  cursor: pointer;
}

.debug-title {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: bold;
  letter-spacing: 2px;
  text-shadow: 0 0 10px var(--neon);
}

.pulse {
  width: 8px;
  height: 8px;
  background: var(--neon-green);
  border-radius: 50%;
  animation: pulse 1.5s infinite;
  box-shadow: 0 0 10px var(--neon-green);
}

@keyframes pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.5; transform: scale(0.8); }
}

.debug-controls {
  display: flex;
  gap: 4px;
}

.tab {
  padding: 4px 8px;
  border-radius: 4px;
  cursor: pointer;
  transition: all 0.2s;
  color: rgba(0, 255, 255, 0.5);
}

.tab:hover {
  color: var(--neon);
}

.tab.active {
  background: rgba(0, 255, 255, 0.2);
  color: var(--neon);
  text-shadow: 0 0 5px var(--neon);
}

.debug-body {
  max-height: 250px;
  overflow-y: auto;
}

.debug-body::-webkit-scrollbar {
  width: 4px;
}

.debug-body::-webkit-scrollbar-thumb {
  background: var(--neon);
  border-radius: 2px;
}

.tab-content {
  padding: 12px;
}

.state-item {
  display: flex;
  justify-content: space-between;
  padding: 6px 0;
  border-bottom: 1px solid rgba(0, 255, 255, 0.1);
}

.key {
  color: var(--neon-pink);
}

.value {
  color: var(--neon-green);
}

.value.boolean { color: #ff0; }
.value.number { color: #0ff; }
.value.string { color: #0f0; }

.event-item {
  display: flex;
  gap: 12px;
  padding: 4px 0;
  border-left: 2px solid var(--neon-pink);
  padding-left: 8px;
  margin-bottom: 4px;
}

.event-time {
  color: rgba(255, 255, 255, 0.4);
  font-size: 10px;
}

.event-name {
  color: var(--neon-pink);
}

.empty {
  text-align: center;
  color: rgba(255, 255, 255, 0.3);
  padding: 20px;
}

.console-input {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px;
  background: rgba(0, 0, 0, 0.5);
  border-radius: 4px;
  margin-bottom: 8px;
}

.prompt {
  color: var(--neon-green);
  font-weight: bold;
}

.console-input input {
  flex: 1;
  background: transparent;
  border: none;
  color: #fff;
  font-family: inherit;
  font-size: 12px;
  outline: none;
}

.console-output {
  max-height: 150px;
  overflow-y: auto;
}

.log-item {
  display: flex;
  gap: 8px;
  padding: 4px 0;
  font-size: 11px;
}

.log-item.result .log-prefix {
  color: var(--neon-green);
}

.log-item.error .log-prefix {
  color: #f44;
}

.log-item.error .log-content {
  color: #f88;
}

.log-content {
  color: rgba(255, 255, 255, 0.8);
  word-break: break-all;
}

.action-btn {
  width: 100%;
  margin-top: 8px;
  padding: 6px;
  background: transparent;
  border: 1px solid var(--neon);
  color: var(--neon);
  border-radius: 4px;
  cursor: pointer;
  font-family: inherit;
  transition: all 0.2s;
}

.action-btn:hover {
  background: rgba(0, 255, 255, 0.2);
  box-shadow: 0 0 10px rgba(0, 255, 255, 0.3);
}

.action-btn.danger {
  border-color: #f44;
  color: #f44;
}

.action-btn.danger:hover {
  background: rgba(255, 68, 68, 0.2);
}

.debug-footer {
  display: flex;
  justify-content: space-around;
  padding: 8px;
  background: rgba(0, 0, 0, 0.5);
  border-top: 1px solid rgba(0, 255, 255, 0.2);
}

.metric {
  color: rgba(255, 255, 255, 0.5);
  font-size: 10px;
}

.metric-value {
  color: var(--neon-green);
  font-weight: bold;
}


# themes

id: theme-dark
name: Dark
description: Default dark theme
metadata: {"author":"system","version":"1.0.0","tags":["dark","default"]}
created_at: 2026-02-13 10:50:57
updated_at: 2026-02-13 10:50:57
variables:
{"colors":{"bg-primary":"#0f0f14","bg-secondary":"#16161d","bg-hover":"#1e1e28","bg-tertiary":"#252530","border-color":"#2a2a3a","border-hover":"#3a3a4a"},"text":{"text-primary":"#e4e4e7","text-secondary":"#a1a1aa","text-muted":"#52525b","text-inverse":"#0f0f14"},"accent":{"accent":"#6366f1","accent-hover":"#818cf8","accent-muted":"rgba(99, 102, 241, 0.2)","accent-text":"#ffffff"},"semantic":{"success":"#22c55e","success-bg":"rgba(34, 197, 94, 0.1)","warning":"#eab308","warning-bg":"rgba(234, 179, 8, 0.1)","error":"#ef4444","error-bg":"rgba(239, 68, 68, 0.1)","info":"#3b82f6","info-bg":"rgba(59, 130, 246, 0.1)"},"spacing":{"radius-sm":"4px","radius-md":"8px","radius-lg":"12px","radius-full":"9999px"},"typography":{"font-sans":"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif","font-mono":"'JetBrains Mono', 'Fira Code', Consolas, monospace"},"effects":{"shadow-sm":"0 1px 2px rgba(0,0,0,0.2)","shadow-md":"0 4px 6px rgba(0,0,0,0.3)","shadow-lg":"0 10px 15px rgba(0,0,0,0.4)","transition-fast":"0.15s ease","transition-normal":"0.2s ease"}}


id: theme-light
name: Light
description: Clean light theme
metadata: {"author":"system","version":"1.0.0","tags":["light"]}
created_at: 2026-02-13 10:50:57
updated_at: 2026-02-13 10:50:57
variables:
{"colors":{"bg-primary":"#ffffff","bg-secondary":"#f4f4f5","bg-hover":"#e4e4e7","bg-tertiary":"#d4d4d8","border-color":"#d4d4d8","border-hover":"#a1a1aa"},"text":{"text-primary":"#18181b","text-secondary":"#52525b","text-muted":"#a1a1aa","text-inverse":"#ffffff"},"accent":{"accent":"#4f46e5","accent-hover":"#4338ca","accent-muted":"rgba(79, 70, 229, 0.1)","accent-text":"#ffffff"},"semantic":{"success":"#16a34a","success-bg":"rgba(22, 163, 74, 0.1)","warning":"#ca8a04","warning-bg":"rgba(202, 138, 4, 0.1)","error":"#dc2626","error-bg":"rgba(220, 38, 38, 0.1)","info":"#2563eb","info-bg":"rgba(37, 99, 235, 0.1)"},"spacing":{"radius-sm":"4px","radius-md":"8px","radius-lg":"12px","radius-full":"9999px"},"typography":{"font-sans":"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif","font-mono":"'JetBrains Mono', 'Fira Code', Consolas, monospace"},"effects":{"shadow-sm":"0 1px 2px rgba(0,0,0,0.05)","shadow-md":"0 4px 6px rgba(0,0,0,0.07)","shadow-lg":"0 10px 15px rgba(0,0,0,0.1)","transition-fast":"0.15s ease","transition-normal":"0.2s ease"}}


