Newer
Older
bugtrail / packages / extension / src / content / overlay / RecorderBar.vue
<script setup lang="ts">
import { onMounted, onUnmounted, ref } from "vue";
import browser from "webextension-polyfill";

const emit = defineEmits<{
  (e: "note"): void;
  (e: "stop"): void;
}>();

const stepCount = ref(0);
let timer: ReturnType<typeof setInterval> | null = null;

async function refresh() {
  try {
    const response = (await browser.runtime.sendMessage({ type: "recorder_state_request" })) as {
      ok: boolean;
      data?: { stepCount: number };
    };
    if (response?.data) stepCount.value = response.data.stepCount;
  } catch {
    // background gone (update/reload) — bar will refresh on next tick
  }
}

onMounted(() => {
  void refresh();
  timer = setInterval(() => void refresh(), 1000);
});
onUnmounted(() => {
  if (timer) clearInterval(timer);
});
</script>

<template>
  <div class="recorder-bar">
    <span class="recorder-dot" />
    <span class="recorder-label">REC</span>
    <span class="recorder-steps">{{ stepCount }} step{{ stepCount === 1 ? "" : "s" }}</span>
    <button type="button" class="recorder-btn" title="Annotate an element" @click="emit('note')">
      <i class="ph ph-note-pencil" /> Note
    </button>
    <button type="button" class="recorder-btn recorder-btn-stop" title="Stop and submit recording" @click="emit('stop')">
      <i class="ph ph-stop" /> Stop
    </button>
  </div>
</template>

<style scoped>
.recorder-bar {
  position: fixed;
  right: 16px;
  bottom: 16px;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  background: var(--color-surface, #1a1c2b);
  border: 2px solid var(--color-danger, #f7768e);
  color: var(--color-text, #c0caf5);
}
.recorder-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--color-danger, #f7768e);
  animation: ltt-pulse 1.2s ease-in-out infinite;
}
@keyframes ltt-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.3; }
}
.recorder-label {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.1em;
}
.recorder-steps {
  font-size: 12px;
  opacity: 0.8;
  min-width: 60px;
}
.recorder-btn {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 10px;
  border: 2px solid var(--color-border, #2f334d);
  background: transparent;
  color: inherit;
  font: inherit;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  cursor: pointer;
}
.recorder-btn:hover {
  border-color: var(--color-accent, #7aa2f7);
}
.recorder-btn-stop {
  border-color: var(--color-danger, #f7768e);
  color: var(--color-danger, #f7768e);
}
.recorder-btn-stop:hover {
  background: rgba(247, 118, 142, 0.12);
}
</style>