zzzUI

Objectives

React 任务目标追踪组件:深色横条上方为斜体标题,每个目标前带一个斜切标记,已完成的目标以删除线标出。

安装

terminal
# once per project: where @zzzui items come frompnpm dlx shadcn@latest registry add @zzzui=https://zzzui.catforest.dev/r/{name}.jsonpnpm dlx shadcn@latest add @zzzui/objectives

示例

班次任务目标

Night shift

Done: Reach the rail yards
Current: Load the sealed crates2 / 5
To do: Cross the river before the gate shuts
To do: Hand over at the North gate
objectives-shift.tsx
import { useState } from "react";import { Button } from "@/components/zero/button";import {  Objective,  ObjectiveCount,  ObjectiveDescription,  type ObjectiveState,  Objectives,  ObjectivesHeader,  ObjectiveTitle,} from "@/components/zero/objectives";const steps = [  "Reach the rail yards",  "Load the sealed crates",  "Cross the river before the gate shuts",  "Hand over at the North gate",];export default function ObjectivesShift() {  const [step, setStep] = useState(1);  const [crates, setCrates] = useState(2);  const [failed, setFailed] = useState(false);  const state = (index: number): ObjectiveState =>    index < step      ? "done"      : index === step        ? failed          ? "failed"          : "active"        : "pending";  const advance = () => {    if (step === 1 && crates < 5) setCrates((n) => n + 1);    else setStep((s) => Math.min(steps.length, s + 1));  };  return (    <div className="grid justify-items-start gap-5">      <Objectives aria-label="Night shift">        <ObjectivesHeader>Night shift</ObjectivesHeader>        {steps.map((title, index) => (          <Objective key={title} state={state(index)}>            <ObjectiveTitle>{title}</ObjectiveTitle>            {index === 1 ? <ObjectiveCount>{crates} / 5</ObjectiveCount> : null}            {index === 2 && state(index) === "active" ? (              <ObjectiveDescription>                The gate shuts at 02:00.              </ObjectiveDescription>            ) : null}          </Objective>        ))}      </Objectives>      <div className="flex flex-wrap gap-3">        <Button size="sm" onClick={advance} disabled={failed}>          Next        </Button>        <Button          variant="danger"          size="sm"          onClick={() => setFailed(true)}          disabled={failed || step >= steps.length}        >          Fail it        </Button>        <Button          variant="ghost"          size="sm"          onClick={() => {            setStep(1);            setCrates(2);            setFailed(false);          }}        >          Start over        </Button>      </div>    </div>  );}

行为

每个目标前有一个斜切标记:未开始时为空框,进行中为强调色边框,完成时填满强调色并带对勾,失败时为红色并带叉号。已完成或已失败的目标,标题会从左端开始画出一道删除线。背后的横条向右渐隐,因此可以叠放在地图或场景之上。

状态也会以文字告知读屏软件(「Done:」「Current:」)。ObjectiveCount 位于该行末尾;ObjectiveDescription 位于标题下方。

属性

Objective

属性类型默认值说明
state"pending" | "active" | "done" | "failed""pending"标记样式,以及标题的绘制方式。
labelsPartial<Record<ObjectiveState, string>>objectiveLabels读屏软件在标题前读出的状态说明(如 "Done: "),按状态分别设定。

Objectives, ObjectivesHeader, ObjectiveTitle, ObjectiveCount, ObjectiveDescription