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

@dienzt/shift-wisher

v3.0.0

Published

Vue 3 component for shift preference collection with calendar, undo/redo and scoring

Readme

ShiftWisher

Eine Vue 3-Komponente zur Erfassung von Schicht- und Dienstwünschen. Zeigt einen monatsbasierten Kalender mit Infinite-Scroll, in dem Mitarbeiter Verfügbarkeiten und Präferenzen eintragen können.

Features

  • Klick auf einen Tag zyklisch zwischen Bevorzugt → Nicht verfügbar → Verfügbar wechseln
  • Drag-Selektion mehrerer Tage (Maus und Touch) mit Modal zur Bulk-Zuweisung
  • Diensteinschränkung: Wunsch auf einen spezifischen Dienst eingrenzen (im Modal und im Notiz-Popover)
  • Notizen pro Tag/Dienst über das ✎-Icon
  • Undo/Redo (Ctrl+Z / Ctrl+Shift+Z) mit 50-Schritt-Historie
  • Wunschzeitraum (wishRequest) — hervorgehobener Bereich, Kalender scrollt beim Mounten dorthin
  • Punktebewertung — optionales Scoring relativ zur Stellenkapazität mit konfigurierbaren Regeln
  • Feiertage optional per Prop einspeisbar, mit eigenem Darstellungsstil
  • Wochenenden visuell hervorgehoben
  • Vollständig touch-optimiert (mobile-first)
  • Infinite-Scroll über mehrere Monate

Installation

npm install @dienzt/shift-wisher

vue muss als Peer-Dependency bereits im Projekt vorhanden sein:

npm install vue

Verwendung

<template>
  <ShiftWisher
    title="Dienstwünsche Mai"
    :shifts="shifts"
    :holidays="holidays"
    :wish-request="{ from: '2025-05-01', to: '2025-05-31' }"
    :points-base="100"
    @update:wishes="onWishesChanged"
    @update:score="onScoreChanged"
  />
</template>

<script setup lang="ts">
import { ShiftWisher, getGermanFederalHolidays } from '@dienzt/shift-wisher'
import type { SimpleShift, WishRow, WishScore } from '@dienzt/shift-wisher'

const shifts: SimpleShift[] = [
  { id: 'f', name: 'Frühschicht',  color: '#f59e0b' },
  { id: 's', name: 'Spätschicht',  color: '#6366f1' },
  { id: 'n', name: 'Nachtschicht', color: '#1d4ed8' },
]

const holidays = [
  ...getGermanFederalHolidays(2025),
  ...getGermanFederalHolidays(2026),
]

function onWishesChanged(wishes: WishRow[]) {
  // z.B. in Backend persistieren
}

function onScoreChanged(score: WishScore | null) {
  console.log(score?.percentage, score?.rating)
}
</script>

Props

| Prop | Typ | Default | Beschreibung | |---|---|---|---| | title | string | 'Schichtwünsche' | Titel in der Toolbar | | personId | string | — | Optionale ID der Person (für externe Zuordnung) | | shifts | SimpleShift[] | — | Verfügbare Diensttypen für die Diensteinschränkung im Modal/Popover | | holidays | string[] | — | ISO-Datumsstrings ('YYYY-MM-DD') der Feiertage | | wishRequest | WishRequest | — | Zeitraum zur Wunschabgabe; wird hervorgehoben, Kalender scrollt beim Mounten dorthin | | pointsBase | number | — | Stellenkapazität in % (z.B. 100 = Vollzeit). Aktiviert die Punkteanzeige (zusammen mit wishRequest) | | pointsRules | PointsRules | Standardregeln | Optionale angepasste Punktwerte (siehe Punkte-System) |


Events

| Event | Payload | Beschreibung | |---|---|---| | update:wishes | WishRow[] | Wird bei jeder Änderung emittiert | | update:score | WishScore \| null | Wird bei jeder Änderung emittiert; null wenn pointsBase nicht gesetzt |


Bestehende Wünsche laden

Da useWishStore ein Modul-Level-Singleton ist, werden Wünsche direkt über die Store-Funktion geladen — ohne zusätzliches Prop:

import { useWishStore } from '@dienzt/shift-wisher'
import type { WishRow } from '@dienzt/shift-wisher'

const { loadWishes } = useWishStore()

// Beim Initialisieren (z.B. nach API-Call):
const wishes: WishRow[] = await fetchWishesFromBackend()
loadWishes(wishes)

Feiertage

import { getGermanFederalHolidays, getAustrianHolidays } from '@dienzt/shift-wisher'

// Deutsche Bundesfeiertage + optionale länderspezifische Zusatztage
const holidays = getGermanFederalHolidays(2025, [
  '2025-01-06',  // Heilige Drei Könige (BY, BW, ST)
  '2025-11-01',  // Allerheiligen (BY, BW, NW, RP, SL)
])

Beide Funktionen akzeptieren ein optionales zweites Array für länderspezifische Feiertage.


Punkte-System

Wenn pointsBase und wishRequest gesetzt sind, wird eine Punktebewertung oberhalb des Kalenders angezeigt. Ungünstige Tage (Fr/Sa/So/Feiertag) vergeben mehr Punkte bei Verfügbarkeit.

Standardpunktwerte:

| Tag | Bevorzugt | Verfügbar | Nicht verfügbar | |---|---|---|---| | Mo–Do | 2 | 1 | 0 | | Fr/Sa/So/Feiertag | 3 | 2 | 0 |

Bewertungsschema:

| Rating | Prozent | |---|---| | Sehr gut | ≥ 100 % | | Gut | ≥ 80 % | | Ausreichend | ≥ 60 % | | Unzureichend | < 60 % |

Eigene Punktregeln:

import type { PointsRules } from '@dienzt/shift-wisher'

const rules: PointsRules = {
  regular:     { preferred: 2, available: 1, unavailable: -1 },
  unfavorable: { preferred: 4, available: 3, unavailable: -2 },
}
<ShiftWisher :points-base="80" :points-rules="rules" :wish-request="..." />

Typen

type WishType = 'preferred' | 'unavailable'

interface WishRow {
  id:       string
  dayIso:   string    // 'YYYY-MM-DD'
  shiftId?: string    // undefined = Ganztageswunsch
  type:     WishType
  note?:    string
}

interface SimpleShift {
  id:    string
  name:  string
  color: string       // CSS-Farbwert
}

interface WishRequest {
  from: string        // 'YYYY-MM-DD'
  to:   string        // 'YYYY-MM-DD'
}

interface WishScore {
  earned:     number
  target:     number
  percentage: number
  rating:     'sehr-gut' | 'gut' | 'ausreichend' | 'unzureichend'
  label:      string
}

interface PointsRules {
  regular:     { preferred: number; available: number; unavailable: number }
  unfavorable: { preferred: number; available: number; unavailable: number }
}

Entwicklung

npm run dev               # Vite Dev-Server
npm run test:unit         # Vitest (Watch-Modus)
npm run test:unit -- --run  # Einmaliger Testlauf
npm run type-check        # vue-tsc
npm run build             # App-Build (Type-check + Vite)
npm run build:lib         # Library-Build → dist/

npm publish führt automatisch Tests und Library-Build aus (prepublishOnly).


Projektstruktur

src/
├── index.ts             # Öffentlicher Library-Einstiegspunkt
├── components/
│   ├── ShiftWisher.vue      # Haupt-Komponente (Props, Events, Layout)
│   ├── CalendarView.vue     # Monatsraster, Drag-Selektion
│   ├── WishModal.vue        # Modal für Multi-Tag-Selektion inkl. Dienstauswahl
│   ├── NotePopover.vue      # Notiz-/Dienst-Popover für Einzeltag
│   ├── WishScoreDisplay.vue # Punktebalken mit Rating
│   └── ToastNotification.vue
├── composables/
│   ├── useWishStore.ts      # Singleton-Store, Undo/Redo
│   ├── useDragSelect.ts     # Drag-Selektion (Maus + Touch)
│   ├── useInfiniteScroll.ts # Monatsgenerierung per IntersectionObserver
│   ├── useDateHelpers.ts    # Datumsformatierung, Kalenderaufbau
│   ├── useHolidays.ts       # Deutsche/österreichische Feiertage
│   ├── useWishPoints.ts     # Punkte-Berechnung und -Regeln
│   └── useToast.ts
└── types/
    └── wish.types.ts