Skip to content

Repository files navigation

pinpoint

Pinpoint is an engine for displaying hierarchical keys that identify the Earth's species.

Install

npm install @sfgrp/pinpoint

Usage

<script setup>
import { VuePinpoint } from '@sfgrp/pinpoint'
import '@sfgrp/pinpoint/style.css'
</script>

<template>
  <VuePinpoint
    :lead-id="103"
    base-url="https://sfg.taxonworks.org/api/v1"
    project-token="YOUR_TOKEN"
  />
</template>

Props

Prop Type Required Description
leadId number | string yes Id of the lead the key starts on.
baseUrl string yes TaxonWorks API base url.
projectToken string yes TaxonWorks project token.
fetcher (id: number) => Promise<KeyResponse> no Load the key payload from somewhere other than a TaxonWorks server.
allowHtml boolean no Render lead text as HTML. TaxonWorks marks up taxon names, so this is on by default. Defaults to true.

Nothing is requested until leadId, baseUrl and projectToken are all set, so binding them to values that arrive asynchronously is safe.

Events

Event Payload Fired when
start A load begins.
loading A load begins.
end KeyResponse A load resolves.
error Error A load rejects.

Exposed methods

const pinpoint = ref()

pinpoint.value.getState()        // reactive store state
pinpoint.value.setCurrentNode(9) // navigate to a node by id
pinpoint.value.isLoading         // computed<boolean>

Slots

Every slot is declared on <VuePinpoint>, no matter how deep it renders.

Figures

Three levels of control, from most to least of the built-in UI replaced.

#figures — replace the whole gallery of a lead

<VuePinpoint v-bind="config">
  <template #figures="{ figures, node, open }">
    <MyGallery
      :images="figures"
      @select="(index) => open(index)"
    />
  </template>
</VuePinpoint>
Slot prop Type Description
figures Figure[] Figures attached to this lead.
node Node | null The lead the figures belong to.
open (index: number) => void Opens the viewer on the given figure.

#figure — replace a single thumbnail

<template #figure="{ figure, index, open }">
  <img
    :src="figure.thumb"
    :alt="figure.caption ?? ''"
    @click="open"
  />
</template>
Slot prop Type Description
figure Figure The figure to render.
index number Its position in figures.
figures Figure[] The full list, for context.
node Node | null The lead the figure belongs to.
open () => void Opens the viewer on this figure.

#figure-viewer — keep the thumbnails, bring your own image viewer

This is usually what you want: pinpoint renders the thumbnails and tracks which figure is active, your component does the actual viewing.

<template #figure-viewer="{ figure, figures, index, close, next, previous }">
  <MyLightbox
    :items="figures"
    :start-index="index"
    @close="close"
  />
</template>
Slot prop Type Description
figure Figure The active figure.
figures Figure[] The full list, so you can offer navigation.
index number Index of the active figure.
node Node | null The lead the figures belong to.
close () => void Closes the viewer.
next () => void Advances to the next figure (wraps around).
previous () => void Goes back one figure (wraps around).

The slot only renders once a thumbnail has been activated, so there is no need to guard on visibility yourself.

Other slots

Slot Slot props Replaces
title { title, metadata } The key title.
loading { leadId } Shown while a key loads. See below.
error { error } The error message.
text { text, node } Lead text, wherever it renders.
target { label, id, node } The target label of a lead.
couplet-title { node, coupletNumber } "Couplet N".
previous-couplets-title "Previous couplets".
button-up-label { node } "Up".
button-go-label { node } "Go".
button-next-label { node } "Next".
figure-next-label The viewer's next arrow.
figure-previous-label The viewer's previous arrow.

#loading

Rendered while a key is in flight, and removed once it resolves or fails. Nothing at all is rendered when the slot is not provided, so this is opt-in.

<VuePinpoint v-bind="config">
  <template #loading>
    <MySpinner />
  </template>
</VuePinpoint>

The rest of the key stays mounted underneath while loading, so an overlay works without the content flickering out. If you would rather drive the state from outside, the loading/end/error events still fire, and isLoading is available on the component instance.

The Figure type

type Figure = {
  id: number | null
  caption: string | null
  label: string | null
  position: number
  contentType: string | null
  thumb: string     // small preview
  image: string     // medium size, used by the built-in thumbnails
  original: string  // full size, project token appended
  source: unknown   // the untouched API payload
}

source is the escape hatch: anything the adapters do not normalize is still reachable from your own viewer.

Using a data source other than TaxonWorks

fetcher replaces the request for the key payload. It receives the lead id and must resolve with the raw payload, in the same shape the TaxonWorks endpoint returns.

<VuePinpoint
  :lead-id="1"
  base-url="https://sfg.taxonworks.org/api/v1"
  project-token="YOUR_TOKEN"
  :fetcher="(id) => fetch(`/keys/${id}.json`).then((r) => r.json())"
/>

baseUrl and projectToken are still required with a fetcher: the API returns figure paths relative to the server (/api/v1/images/…), and the adapters need both to turn them into fetchable urls.

Development

npm run dev        # demo app
npm test           # unit + component tests
npm run typecheck  # vue-tsc
npm run build:lib  # library bundle + type declarations

About

Pinpoint is a engine for displaying hierarchical keys that identify the Earth's speices.

Resources

Stars

0 stars

Watchers

5 watching

Forks

Releases

Packages

Used by

Contributors

Languages