All files / src/components/list ConflictBanner.vue

100% Statements 7/7
100% Branches 11/11
100% Functions 2/2
100% Lines 7/7

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47      5x 5x       5x           2x 2x               1x               5x                              
<script setup lang="ts">
import type { Conflict } from '../../crdt/ConflictDetector'
 
const props = defineProps<{ conflicts: Conflict[] }>()
const emit = defineEmits<{ dismiss: [] }>()
</script>
 
<template>
  <Transition name="banner">
    <div
      v-if="conflicts.length > 0"
      class="mx-4 mt-2 flex items-start gap-3 bg-ctp-yellow/10 border border-ctp-yellow/25 rounded-xl px-4 py-3"
    >
      <span class="text-ctp-yellow text-base shrink-0 mt-0.5">⚡</span>
      <div class="flex-1 min-w-0">
        <p class="text-sm font-medium text-ctp-yellow">
          {{ conflicts.length }} gleichzeitige {{ conflicts.length === 1 ? 'Änderung' : 'Änderungen' }} erkannt
        </p>
        <p class="text-xs text-ctp-yellow/70 mt-0.5">
          Automatisch zusammengeführt — neueste Änderung hat Vorrang.
        </p>
      </div>
      <button
        @click="emit('dismiss')"
        class="text-ctp-yellow/60 hover:text-ctp-yellow transition-colors shrink-0"
        aria-label="Schließen"
      >
        <svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
          <path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
        </svg>
      </button>
    </div>
  </Transition>
</template>
 
<style scoped>
.banner-enter-active,
.banner-leave-active {
  transition: all 0.25s ease;
}
.banner-enter-from,
.banner-leave-to {
  opacity: 0;
  transform: translateY(-8px);
}
</style>