Contract · J-104
Sealed crate run
Objectives
To do: Collect five sealed crates
To do: Cross before the gate shuts
To do: Hand over at the North gate
Threat
Reward
3,100cr
1 legendaryNight only
React 任务简报界面:委托名称以故障效果浮现在路线图上,旁边列出任务目标、威胁等级与报酬,按住即可接受委托。
# 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/mission-briefingContract · J-104
3,100cr
1 legendaryNight only
import { useState } from "react";import { Badge } from "@/components/zero/badge";import { Button } from "@/components/zero/button";import { Counter } from "@/components/zero/counter";import { CutIn, CutInContent, CutInDescription, CutInEyebrow, CutInTitle,} from "@/components/zero/cut-in";import { Gauge, GaugeLabel, GaugeValue } from "@/components/zero/gauge";import { HoldButton } from "@/components/zero/hold-button";import { CrateIcon } from "@/components/zero/icons/crate";import { KeyIcon } from "@/components/zero/icons/key";import { KitIcon } from "@/components/zero/icons/kit";import { Inventory, InventorySlot } from "@/components/zero/inventory";import { Kbd } from "@/components/zero/kbd";import { Objective, Objectives, ObjectivesHeader, ObjectiveTitle,} from "@/components/zero/objectives";/* * A briefing before a job: the contract's name glitching in over a route map, what has to be * done, how dangerous it is, and what it pays. Accepting it is held, so it is never taken by a * stray click; once taken, a cut-in announces it. The map is drawn in place (a grid, a route, two * marks), so swap it for your own picture. */const route = "M40 196 L120 150 L170 162 L250 92 L330 70 L410 34";export function MissionBriefing() { const [taken, setTaken] = useState(false); const [announce, setAnnounce] = useState(false); return ( // two columns once its own box is wide enough, wherever it is placed <div className="@container w-full max-w-5xl"> <article aria-labelledby="briefing-title" className="grid border-(length:--zero-stroke) border-zero-ink bg-zero-surface bg-(image:--zero-hatch) @4xl:grid-cols-[1.25fr_1fr]" > <div className="grid content-start gap-5 bg-zero-void p-6"> <div className="grid gap-3"> <p className="flex items-center gap-2.5 font-black font-zero text-zero-accent text-zero-sm uppercase italic tracking-[0.14em] before:h-[0.9em] before:w-[0.45em] before:-skew-x-(--zero-slant) before:bg-zero-accent"> Contract · J-104 </p> <h2 id="briefing-title" className="glitch font-black font-zero text-zero-2xl italic" > Sealed crate run </h2> </div> <figure className="grid gap-2"> <svg viewBox="0 0 440 230" role="img" aria-label="Route from the rail yards to the North gate, across the river" className="w-full border-(length:--zero-stroke-thin) border-zero-line bg-zero-ground" > <defs> <pattern id="briefing-grid" width="22" height="22" patternUnits="userSpaceOnUse" > <path d="M22 0H0V22" fill="none" stroke="var(--color-zero-line)" strokeWidth="1" /> </pattern> </defs> <rect width="440" height="230" fill="url(#briefing-grid)" /> <path d="M0 120 C80 100 140 140 220 118 S360 80 440 100 L440 128 C360 108 300 150 220 146 S80 128 0 148Z" fill="var(--color-zero-raised)" /> <path d={route} fill="none" stroke="var(--color-zero-accent)" strokeWidth="4" strokeDasharray="10 6" /> <polygon points="36,188 52,188 48,204 32,204" fill="var(--color-zero-text)" /> <polygon points="406,26 422,26 418,42 402,42" fill="var(--color-zero-accent)" /> </svg> <figcaption className="flex justify-between font-medium font-zero-text text-zero-sm text-zero-text-3"> <span>Rail yards</span> <span>River crossing</span> <span className="text-zero-accent">North gate</span> </figcaption> </figure> </div> <div className="grid content-start gap-6 p-6"> <Objectives aria-label="What has to be done" className="max-w-none"> <ObjectivesHeader>Objectives</ObjectivesHeader> <Objective state={taken ? "active" : "pending"}> <ObjectiveTitle>Collect five sealed crates</ObjectiveTitle> </Objective> <Objective> <ObjectiveTitle>Cross before the gate shuts</ObjectiveTitle> </Objective> <Objective> <ObjectiveTitle>Hand over at the North gate</ObjectiveTitle> </Objective> </Objectives> <Gauge value={3} max={5} segments={5} tone="danger"> <GaugeLabel>Threat</GaugeLabel> <GaugeValue>{() => "High"}</GaugeValue> </Gauge> <div className="grid gap-3"> <span className="font-black font-zero text-zero-sm uppercase italic tracking-[0.06em]"> Reward </span> <div className="flex flex-wrap items-center gap-x-6 gap-y-3"> <p className="flex items-baseline gap-1.5"> <Counter value={3100} className="text-zero-xl" /> <span className="font-black font-zero text-zero-accent italic"> cr </span> </p> <Inventory columns={3} aria-label="Loot" className="gap-1"> <InventorySlot rarity="legendary" aria-label="Gate key"> <KeyIcon /> </InventorySlot> <InventorySlot rarity="rare" count={2} aria-label="Sealed crate, 2" > <CrateIcon /> </InventorySlot> <InventorySlot rarity="uncommon" count={3} aria-label="Repair kit, 3" > <KitIcon /> </InventorySlot> </Inventory> </div> <p className="flex flex-wrap gap-2"> <Badge rarity="legendary">1 legendary</Badge> <Badge variant="secondary">Night only</Badge> </p> </div> <div className="flex flex-wrap items-center justify-end gap-3 border-zero-line border-t-(length:--zero-stroke-thin) pt-5"> {taken ? ( <Button variant="ghost" onClick={() => setTaken(false)}> Hand it back </Button> ) : ( <> <Button variant="ghost">Decline</Button> <HoldButton hotkey="e" onConfirm={() => { setTaken(true); setAnnounce(true); }} > <Kbd>E</Kbd> Hold to accept </HoldButton> </> )} </div> </div> <CutIn open={announce} onOpenChange={setAnnounce}> <CutInContent> <CutInEyebrow>Job taken</CutInEyebrow> <CutInTitle>Sealed crate run</CutInTitle> <CutInDescription> Rail yards → North gate · 3,100 cr </CutInDescription> </CutInContent> </CutIn> </article> </div> );}标题以故障效果浮现在地图上。地图直接以 SVG 绘制(网格、河流、路线与两个标记),可替换为自己的图片。旁边依次是任务目标、五格的威胁数值条,以及置于物品格中的报酬与战利品。
接受委托需要按住按钮(或按住 E),避免误点接受;接受委托后,Cut-in 宣告任务开始,第一项目标成为当前目标。只要代码块自身宽度足够(容器查询),无论置于何处都排成两栏。
由 Objectives、Gauge、Counter、Inventory、Badge、Hold button、Cut-in、Kbd、Button 组成,安装此代码块时会一并安装这些组件。