# Downtime Log

A compact log of machine stops for shop-floor dashboards. Each row shows when the stop started, a colored reason pill and its length in minutes; long stops turn orange. Select rows with the checkboxes and the footer sums their minutes. Below the list, a 24-hour timeline draws every stop as colored ticks on a ruler per machine. Hover a row to light up its stop on the timeline, or hover a stop to find its row.

<demo-downtime-log>



</demo-downtime-log>

## Installation

```bash
npx shadcn-vue@latest add "https://nxui.geoql.in/r/downtime-log.json"
```

## Usage

```vue
<script setup lang="ts">
  import { ref } from 'vue';
  import DowntimeLog from '~/components/ui/downtime-log/DowntimeLog.vue';
  import type {
    DowntimeReason,
    DowntimeStop,
  } from '~/components/ui/downtime-log/types';

  const reasons: DowntimeReason[] = [
    { value: 'tooling', label: 'Tooling', color: '#f5d03b' },
    { value: 'material', label: 'Material', color: '#3ee0d8' },
    { value: 'maint', label: 'Maint', color: '#a46cf5' },
  ];

  const stops: DowntimeStop[] = [
    {
      id: 's01',
      startedAt: '2026-09-24T14:08',
      reason: 'tooling',
      minutes: 42,
      machine: 'CNC-04',
    },
    {
      id: 's02',
      startedAt: '2026-09-24T09:51',
      reason: 'material',
      minutes: 18,
      machine: 'Weld-1',
    },
  ];

  const selected = ref<string[]>(['s01']);

  function assign(rows: DowntimeStop[]): void {
    console.log('Assign cause to', rows);
  }
</script>

<template>
  <DowntimeLog
    v-model:selected="selected"
    :stops="stops"
    :reasons="reasons"
    now="2026-09-24T16:20"
    @assign="assign"
  />
</template>
```

Times are wall-clock strings (`YYYY-MM-DDTHH:mm`). They are not converted between time zones, so the server and the browser render the same text.

## Props

<table>
<thead>
  <tr>
    <th>
      Prop
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Default
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        stops
      </code>
    </td>
    
    <td>
      <code>
        DowntimeStop[]
      </code>
    </td>
    
    <td>
      —
    </td>
    
    <td>
      The stops to list. See the stop fields below.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        reasons
      </code>
    </td>
    
    <td>
      <code>
        DowntimeReason[]
      </code>
    </td>
    
    <td>
      —
    </td>
    
    <td>
      Reasons with a label and a color. Also the options of the filter.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        now
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      —
    </td>
    
    <td>
      Current time, <code>
        YYYY-MM-DDTHH:mm
      </code>
      
      . The timeline ends here.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        selected
      </code>
    </td>
    
    <td>
      <code>
        string[]
      </code>
    </td>
    
    <td>
      <code>
        []
      </code>
    </td>
    
    <td>
      <code>
        v-model:selected
      </code>
      
      . Ids of the selected stops.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        hidden-reasons
      </code>
    </td>
    
    <td>
      <code>
        string[]
      </code>
    </td>
    
    <td>
      <code>
        []
      </code>
    </td>
    
    <td>
      <code>
        v-model:hidden-reasons
      </code>
      
      . Reasons the filter hides.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        sort
      </code>
    </td>
    
    <td>
      <code>
        DowntimeSort
      </code>
    </td>
    
    <td>
      <code>
        'newest'
      </code>
    </td>
    
    <td>
      <code>
        v-model:sort
      </code>
      
      . <code>
        'newest'
      </code>
      
      , <code>
        'oldest'
      </code>
      
       or <code>
        'longest'
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        machines
      </code>
    </td>
    
    <td>
      <code>
        string[]
      </code>
    </td>
    
    <td>
      stop order
    </td>
    
    <td>
      Timeline tracks, top to bottom.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        title
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        'Downtime Log'
      </code>
    </td>
    
    <td>
      Card title.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        period
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        'this week'
      </code>
    </td>
    
    <td>
      Text after the stop count.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threshold
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        30
      </code>
    </td>
    
    <td>
      Stops longer than this many minutes show their minutes in orange.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        window-hours
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        24
      </code>
    </td>
    
    <td>
      Hours covered by the timeline. It starts on the hour.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        axis-step
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        6
      </code>
    </td>
    
    <td>
      Hours between x-axis labels.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        tick-minutes
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        20
      </code>
    </td>
    
    <td>
      Minutes between two ruler ticks. A stop colors the ticks it covers.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        visible-rows
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        5
      </code>
    </td>
    
    <td>
      Rows shown before the list scrolls.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        class
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        ''
      </code>
    </td>
    
    <td>
      Extra classes for the root element.
    </td>
  </tr>
</tbody>
</table>

## Stop fields

<table>
<thead>
  <tr>
    <th>
      Field
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        id
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      Unique id. Links the row to its timeline.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        startedAt
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      Start time, <code>
        YYYY-MM-DDTHH:mm
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        reason
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      A <code>
        DowntimeReason
      </code>
      
       value.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        minutes
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      Length of the stop.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        machine
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      Machine that stopped.
    </td>
  </tr>
</tbody>
</table>

## Events

<table>
<thead>
  <tr>
    <th>
      Event
    </th>
    
    <th>
      Payload
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        export
      </code>
    </td>
    
    <td>
      <code>
        DowntimeStop[]
      </code>
    </td>
    
    <td>
      The Export button. Sends the filtered, sorted rows.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        assign
      </code>
    </td>
    
    <td>
      <code>
        DowntimeStop[]
      </code>
    </td>
    
    <td>
      The Assign Cause button. Sends the selected stops.
    </td>
  </tr>
</tbody>
</table>

## Accessibility

- Each row is a focusable `role="checkbox"` with `aria-checked`. Space or Enter toggles it. The arrow keys move between rows.
- The header checkbox sets `aria-checked="mixed"` when only some rows are selected.
- The filter is a menu of `menuitemcheckbox` items. Escape or a click outside closes it.
- The selected count and minutes are announced through `aria-live`.
- Each timeline stop has a text label with its machine, reason, time and length.
- Transitions turn off when the user prefers reduced motion.
