npm package: @sketchmonk/floating-comment-vue
Description: A headless component for building figma like floating comments in Vue 3
Latest version: 0.1.0-alpha.6

## FloatingComments Component

The `FloatingComments` component allows users to add and view comments on specific positions within a container. It provides a dialog for adding comments and displays comments at their respective positions.

### Props

- `width`: The width of the container.
- `height`: The height of the container.

### Slots

- `default`: The default slot for the content inside the container.
- `dialog`: Slot for the dialog that appears when adding a comment.
- `comment`: Slot for displaying individual comments.
- `comment-expanded`: Slot for displaying an expanded view of a comment.

### Example Usage

```vue
<template>
  <FloatingComments v-bind="props" v-model:comments="comments">
      <template #default>
          <div class="w-full h-full bg-background">
          </div>
      </template>
      <template #dialog="{ actions, position }">
          <div class="dialog">
              <div class="dialog__title">Add Comment</div>
              <div class="dialog__content">
                  <textarea @keyup.enter="addComment(position); actions.closeDialog()" v-model="content" class="dialog__textarea"></textarea>
              </div>
          </div>
      </template>
      <template #comment="{ comment, actions }">
          <div @click="actions.openComment(comment.id)" class="comment">
              <div class="comment__avatar">
                  {{ comment.data.user.username.charAt(0) }}
              </div>
          </div>
      </template>
      <template #comment-expanded="{ comment }">
          <div class="dialog">
              <div class="dialog__title">{{ comment.data.user.username }}</div>
              <div class="dialog__content">
                  <div class="dialog__description">{{ comment.data.content }}</div>
              </div>
          </div>
      </template>
  </FloatingComments>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { FloatingComments } from 'floating-comment-vue';

const comments = ref([]);
const content = ref('');

const addComment = (position: { x: number, y: number }) => {
    comments.value = [
      ...comments.value,
      {
        id: Math.random().toString(36).substring(7),
        data: {
          user: {
            username: "User",
            profileUrl: "https://avatars.githubusercontent.com/u/1?v=4",
          },
          content: content.value,
          timestamp: new Date().toISOString(),
        },
        position,
      },
    ];
}
</script>

<style lang="css">
* {
    font-family: monospace;
}

:root {
    --background: #defaultd4a373;
    --surface: #fefae0 ;
}

.w-full {
    width: 100%;
}
.h-full {
    height: 100%;
}
.bg-surface {
    background-color: var(--surface);
}
.box {
    border: 3px solid #000;
    box-shadow: 3px 3px 0 #000;
}
.m-4 {
    margin: 1rem;
}

.dialog {
    background-color: var(--surface);
    border: 3px solid #000;
    border-radius: 4px;
    width: 200px;
    box-sizing: border-box;
    box-shadow: 4px 4px 0 #000;
}

.dialog__title {
    font-size: 1.25rem;
    font-weight: bold;
    margin-bottom: 8px;
    padding: 0.5rem 1rem;
    border-bottom: 3px solid #000;
    text-align: center;
}

.dialog__content {
    padding: 1rem;
    box-sizing: border-box;
}

.dialog__textarea {
    width: 100%;
    height: 100px;
    padding: 0.5rem;
    box-sizing: border-box;
    font-size: 1rem;
    border: 3px solid #000;
    border-radius: 4px;
}

.dialog__description {
    font-size: 0.875rem;
    opacity: 0.75;
}

.comment {
    width: 40px;
    height: 40px;
    background-color: var(--surface);
    border: 2px solid #000;
    box-shadow: 2px 2px 0 #000;
    border-radius: 50rem;
    display: flex;
    justify-content: center;
    align-items: center;
    cursor: pointer;
    position: relative;
}

.comment::after {
    content: '';
    position: absolute;
    width: 20px;
    height: 20px;
    border-top: 2px solid #000;
    border-left: 2px solid #000;
    background-color: var(--surface);
    top: -2px;
    left: -2px;
    z-index: 1;
}

.comment__avatar {
    width: 28px;
    height: 28px;
    font-size: 1rem;
    font-weight: bold;
    background-color: #000;
    color: var(--surface);
    border-radius: 50rem;
    display: flex;
    justify-content: center;
    align-items: center;
    z-index: 2;
}
</style>