npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

vue-photo-commenter

v1.0.6

Published

A Vue component for adding comments to specific areas of an image

Readme

Vue Photo Commenter

A Vue 3 component for adding comments to images with pin markers.

Features

  • Draw selection boxes on images to add comments
  • Hover over comment boxes to see comments
  • Click on comment boxes to highlight them
  • Click on comments in the list to highlight corresponding boxes on the image
  • Responsive design that works with any image size
  • Built with Element Plus UI components
  • TypeScript support
  • Customizable comments section component

Installation

npm install vue-photo-commenter

Usage

<template>
  <PhotoCommenter
    :image-url="imageUrl"
    v-model="comments"
    :author="author"
    @submit="handleSubmit"
    @cancel="handleCancel"
  />
</template>

<script setup>
import { ref } from 'vue'
import PhotoCommenter from 'vue-photo-commenter'
import 'vue-photo-commenter/dist/photo-commenter.css'
import { ElMessage, ElLoading } from 'element-plus'
import 'element-plus/dist/index.css'

const imageUrl = 'https://example.com/image.jpg'
const comments = ref([])
const author = ref({
  userId: 'user123',
  name: 'John Doe',
  email: '[email protected]'
})

const handleSubmit = (newComments) => {
  comments.value = newComments
}

const handleCancel = () => {
  console.log('Comment input cancelled')
}
</script>

Props

| Prop | Type | Required | Default | Description | |------|------|----------|---------|-------------| | imageUrl | string | Yes | - | URL of the image to comment on | | modelValue | CommentData[] | Yes | [] | Array of comments (v-model) | | author | Author | Yes | - | Current user's author information | | selectedComment | number | No | null | Index of the currently selected comment |

Events

| Event | Payload | Description | |-------|---------|-------------| | update:modelValue | CommentData[] | Emitted when comments are updated | | submit | CommentData[] | Emitted when a new comment is submitted | | cancel | - | Emitted when comment input is cancelled | | box-click | number | Emitted when a comment box is clicked |

Types

interface Author {
  userId: string
  name: string
  email: string
  role?: string
}

interface CommentData {
  x: number
  y: number
  width: number
  height: number
  text: string
  author: Author
  created_date: string
  replies?: CommentData[]
}

Components

PhotoCommenter

The main component for adding comments to images.

Props

| Prop | Type | Required | Description | |------|------|----------|-------------| | imageUrl | String | Yes | The URL of the image to display | | value | Array | No | Array of comments (v-model) | | selectedComment | Number | No | Index of the currently selected comment |

Events

| Event | Description | Parameters | |-------|-------------|------------| | update:value | Emitted when comments are updated | Array of comments | | submit | Emitted when a new comment is saved | Array of comments | | cancel | Emitted when comment input is cancelled | None |

CommentsSection

A component to display the list of comments with customizable styling.

Props

| Prop | Type | Required | Description | |------|------|----------|-------------| | comments | Array | Yes | Array of comments to display | | styles | Object | No | Custom styles for different parts of the component | | selectedIndex | Number | No | Index of the currently selected comment |

Style Properties

The styles prop accepts an object with the following properties:

interface StyleProps {
  sectionStyles?: CSSProperties;  // Styles for the main container
  titleStyles?: CSSProperties;    // Styles for the "Comments" title
  listStyles?: CSSProperties;     // Styles for the comments list
  commentStyles?: CSSProperties;  // Styles for each comment item
  contentStyles?: CSSProperties;  // Styles for the comment text
  authorStyles?: CSSProperties;   // Styles for the author information
}

Events

| Event | Description | Parameters | |-------|-------------|------------| | comment-click | Emitted when a comment is clicked | Index of the clicked comment |

Slots

| Slot | Description | Props | |------|-------------|-------| | comment | Custom template for each comment | { comment: CommentData } |

Comment Object Structure

Each comment in the array has the following structure:

interface Comment {
  x: number;        // X position (0-1)
  y: number;        // Y position (0-1)
  width: number;    // Width (0-1)
  height: number;   // Height (0-1)
  text: string;     // Comment text
  created_date: string; // ISO date string
}

Dependencies

  • Vue 3
  • Element Plus

Example

Here's a complete example of how to use both components with comment highlighting:

<template>
  <div class="container">
    <h1>Image Commenter Demo</h1>
    <PhotoCommenter
      :image-url="imageUrl"
      v-model="comments"
      :selected-comment="selectedCommentIndex"
      @submit="handleSubmit"
      @cancel="handleCancel"
    />
    <CommentsSection 
      :comments="comments"
      :selected-index="selectedCommentIndex"
      @comment-click="handleCommentClick"
      :styles="{
        titleStyles: { color: '#333', fontSize: '1.5em' },
        listStyles: { marginTop: '20px' },
        commentStyles: { 
          backgroundColor: '#f5f5f5',
          padding: '15px',
          borderRadius: '8px',
          marginBottom: '15px'
        }
      }"
    >
      <template #comment="{ comment }">
        <div class="custom-comment">
          <p class="comment-text">{{ comment.text }}</p>
          <small class="comment-date">
            Added on: {{ new Date(comment.created_date).toLocaleDateString() }}
          </small>
        </div>
      </template>
    </CommentsSection>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { PhotoCommenter, CommentsSection } from 'vue-photo-commenter'
import 'vue-photo-commenter/dist/photo-commenter.css'

const imageUrl = 'https://example.com/your-image.jpg'
const comments = ref([])
const selectedCommentIndex = ref(null)

const handleSubmit = (newComments) => {
  console.log('Comments updated:', newComments)
}

const handleCancel = () => {
  console.log('Comment input cancelled')
}

const handleCommentClick = (index) => {
  selectedCommentIndex.value = index
}
</script>

<style scoped>
.container {
  max-width: 800px;
  margin: 0 auto;
  padding: 20px;
}

.custom-comment {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.comment-text {
  margin: 0;
  font-size: 1.1em;
}

.comment-date {
  color: #666;
  font-size: 0.9em;
}
</style>

License

MIT