@dreamboard-games/cli 0.1.30-alpha.1 → 0.1.30-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +179 -22
- package/dist/agent-verifier/agent-workspace-verifier.mjs +30 -30
- package/dist/agent-verifier/agent-workspace-verifier.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-JH22JNYD.mjs → chunk-3UKQVWLV.mjs} +82 -19
- package/dist/agent-verifier/chunk-3UKQVWLV.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-4WD3YU2E.mjs → chunk-776W3UGV.mjs} +4 -3
- package/dist/agent-verifier/chunk-776W3UGV.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-CJEEA6NJ.mjs → chunk-7WWGFAAU.mjs} +9 -10
- package/dist/agent-verifier/chunk-7WWGFAAU.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-2SZHMP6F.mjs → chunk-A64ZZUZV.mjs} +6 -9
- package/dist/agent-verifier/chunk-A64ZZUZV.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-6A5HRJMQ.mjs → chunk-E7SSWJXJ.mjs} +62 -99
- package/dist/agent-verifier/chunk-E7SSWJXJ.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-2GBBP27W.mjs → chunk-F2DIOJJZ.mjs} +1 -0
- package/dist/agent-verifier/chunk-F2DIOJJZ.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-CFU5EWIC.mjs → chunk-G42BGGG2.mjs} +7 -6
- package/dist/agent-verifier/chunk-G42BGGG2.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-SHUMAVAP.mjs → chunk-H76MT5UR.mjs} +7 -9
- package/dist/agent-verifier/chunk-H76MT5UR.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-7E65UQLY.mjs → chunk-HGMUAL33.mjs} +3 -2
- package/dist/agent-verifier/chunk-HGMUAL33.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-LM3OZLZG.mjs → chunk-IAYRNVUC.mjs} +1 -0
- package/dist/agent-verifier/chunk-IAYRNVUC.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-VYJTHSYR.mjs → chunk-JGT4P4UD.mjs} +2 -1
- package/dist/agent-verifier/chunk-JGT4P4UD.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-CEDUHGNH.mjs → chunk-LUZ7KE6H.mjs} +8 -3
- package/dist/agent-verifier/chunk-LUZ7KE6H.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-2E5P5NWG.mjs → chunk-NAK77WXW.mjs} +58 -126
- package/dist/agent-verifier/chunk-NAK77WXW.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-SYPLYRGB.mjs → chunk-O4YCPU7C.mjs} +116 -15
- package/dist/agent-verifier/chunk-O4YCPU7C.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-BVVNBJM4.mjs → chunk-S34FRJHS.mjs} +2 -1
- package/dist/agent-verifier/chunk-S34FRJHS.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-HJFQDSTU.mjs → chunk-SH5JKYOB.mjs} +6 -5
- package/dist/agent-verifier/chunk-SH5JKYOB.mjs.map +1 -0
- package/dist/agent-verifier/chunk-SKI2ESE5.mjs +44 -0
- package/dist/agent-verifier/{chunk-MINCYHXN.mjs → chunk-TAEQKBJB.mjs} +1 -0
- package/dist/agent-verifier/chunk-TAEQKBJB.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-CEQ2VJWN.mjs → chunk-UIOLGH4A.mjs} +2 -1
- package/dist/agent-verifier/chunk-UIOLGH4A.mjs.map +1 -0
- package/dist/agent-verifier/chunk-UIZNWRM6.mjs +2432 -0
- package/dist/agent-verifier/chunk-UIZNWRM6.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-2QMNAVV4.mjs → chunk-VS573ERH.mjs} +2 -1
- package/dist/agent-verifier/chunk-VS573ERH.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-EOQIV6PS.mjs → chunk-W3N3QJ4V.mjs} +75 -100
- package/dist/agent-verifier/chunk-W3N3QJ4V.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-EIQWDQWJ.mjs → chunk-XGWCY624.mjs} +11 -12
- package/dist/agent-verifier/chunk-XGWCY624.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-7653FPGJ.mjs → chunk-XQXDOBYB.mjs} +3 -2
- package/dist/agent-verifier/chunk-XQXDOBYB.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-MRCUP5SW.mjs → chunk-YE7UAO3T.mjs} +1 -0
- package/dist/agent-verifier/chunk-YE7UAO3T.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-RBDDIIPM.mjs → chunk-ZEELHSY3.mjs} +1 -0
- package/dist/agent-verifier/chunk-ZEELHSY3.mjs.map +1 -0
- package/dist/agent-verifier/{compile-5QSPIOUT.mjs → compile-TEQVA46V.mjs} +24 -25
- package/dist/agent-verifier/compile-TEQVA46V.mjs.map +1 -0
- package/dist/agent-verifier/{global-config-WX3ZZIVU.mjs → global-config-Y2NTSK4R.mjs} +6 -5
- package/dist/{keychain-backend-JHTXAKWC.js → agent-verifier/keychain-backend-SPQWGKZN.mjs} +2 -2
- package/dist/agent-verifier/keychain-backend-SPQWGKZN.mjs.map +1 -0
- package/dist/agent-verifier/{local-files-MTPLP62S.mjs → local-files-JFOQQZDL.mjs} +10 -11
- package/dist/agent-verifier/local-files-JFOQQZDL.mjs.map +1 -0
- package/dist/agent-verifier/local-typecheck-XVGWI75X.mjs +10 -0
- package/dist/agent-verifier/local-typecheck-XVGWI75X.mjs.map +1 -0
- package/dist/agent-verifier/{materialize-workspace-FKALAE2T.mjs → materialize-workspace-ZAVGQQSF.mjs} +17 -18
- package/dist/agent-verifier/materialize-workspace-ZAVGQQSF.mjs.map +1 -0
- package/dist/agent-verifier/{project-state-7GR6BQTQ.mjs → project-state-K576C2TE.mjs} +3 -2
- package/dist/agent-verifier/project-state-K576C2TE.mjs.map +1 -0
- package/dist/{prompt-GMZABCJC.js → agent-verifier/prompt-MJRJMOGQ.mjs} +2 -2
- package/dist/agent-verifier/prompt-MJRJMOGQ.mjs.map +1 -0
- package/dist/agent-verifier/{reducer-bundle-preflight-C73LEXI2.mjs → reducer-bundle-preflight-LXNJUBKL.mjs} +6 -9
- package/dist/agent-verifier/reducer-bundle-preflight-LXNJUBKL.mjs.map +1 -0
- package/dist/agent-verifier/reducer-contract-preflight-TUMQ43JV.mjs +11 -0
- package/dist/agent-verifier/reducer-contract-preflight-TUMQ43JV.mjs.map +1 -0
- package/dist/agent-verifier/{reducer-native-test-harness-GMWBUISX.mjs → reducer-native-test-harness-CHX5MBL5.mjs} +14 -17
- package/dist/agent-verifier/reducer-native-test-harness-CHX5MBL5.mjs.map +1 -0
- package/dist/agent-verifier/static-scaffold-R7SVDRQI.mjs +27 -0
- package/dist/agent-verifier/static-scaffold-R7SVDRQI.mjs.map +1 -0
- package/dist/agent-verifier/{sync-3DUQH32H.mjs → sync-THAI546U.mjs} +31 -37
- package/dist/agent-verifier/sync-THAI546U.mjs.map +1 -0
- package/dist/agent-verifier/{test-P4U5INTD.mjs → test-AFAQFKOB.mjs} +28 -31
- package/dist/agent-verifier/test-AFAQFKOB.mjs.map +1 -0
- package/dist/agent-verifier/workspace-codegen-2ZMQRIKJ.mjs +10 -0
- package/dist/agent-verifier/workspace-codegen-2ZMQRIKJ.mjs.map +1 -0
- package/dist/agent-verifier/{workspace-dependencies-HZ6VVS4G.mjs → workspace-dependencies-NOOQBK6I.mjs} +5 -4
- package/dist/agent-verifier/workspace-dependencies-NOOQBK6I.mjs.map +1 -0
- package/dist/{chunk-C6UAT6EH.js → chunk-N7XPNNUI.js} +9 -12
- package/dist/chunk-N7XPNNUI.js.map +1 -0
- package/dist/chunk-SEGVTWSK.js +44 -0
- package/dist/chunk-SEGVTWSK.js.map +1 -0
- package/dist/{chunk-RS7UXJZV.js → chunk-TAQKH67O.js} +21300 -35881
- package/dist/chunk-TAQKH67O.js.map +1 -0
- package/dist/{global-config-AGFBDFYD.js → global-config-S4ZIPECE.js} +3 -3
- package/dist/global-config-S4ZIPECE.js.map +1 -0
- package/dist/index.js +415 -37
- package/dist/index.js.map +1 -1
- package/dist/internal.js +3 -4
- package/dist/{agent-verifier/keychain-backend-TNOPQV3Z.mjs → keychain-backend-HDF4TZDL.js} +2 -1
- package/dist/{agent-verifier/prompt-3BAINGAQ.mjs → prompt-NDV3AE5L.js} +2 -1
- package/package.json +8 -7
- package/skills/dreamboard/references/building-your-first-game.md +510 -0
- package/skills/dreamboard/references/cli.md +104 -0
- package/skills/dreamboard/references/game-interface.md +548 -0
- package/skills/dreamboard/references/manifest-authoring.md +597 -0
- package/skills/dreamboard/references/quickstart.md +66 -0
- package/skills/dreamboard/references/reducer.md +864 -0
- package/skills/dreamboard/references/rule-authoring.md +147 -0
- package/skills/dreamboard/references/testing.md +249 -0
- package/skills/dreamboard/scripts/events-extract.mjs +218 -0
- package/dist/agent-verifier/chunk-54TAYXUD.mjs +0 -12
- package/dist/agent-verifier/chunk-6UUJEYDV.mjs +0 -213
- package/dist/agent-verifier/chunk-HBNDKQT5.mjs +0 -8381
- package/dist/agent-verifier/chunk-LI3ZR3BI.mjs +0 -41
- package/dist/agent-verifier/chunk-U6OJN7XS.mjs +0 -8092
- package/dist/agent-verifier/chunk-XYDL7GY6.mjs +0 -10
- package/dist/agent-verifier/local-typecheck-QFYYAZOK.mjs +0 -9
- package/dist/agent-verifier/reducer-contract-preflight-22X7DSZW.mjs +0 -10
- package/dist/agent-verifier/static-scaffold-AJMZZQWS.mjs +0 -28
- package/dist/agent-verifier/testing-5K2BJYF2.mjs +0 -674
- package/dist/agent-verifier/workspace-codegen-JDZJRSDV.mjs +0 -11
- package/dist/chunk-2H7UOFLK.js +0 -11
- package/dist/chunk-7FOO4AJI.js +0 -50
- package/dist/chunk-7FOO4AJI.js.map +0 -1
- package/dist/chunk-C6UAT6EH.js.map +0 -1
- package/dist/chunk-RS7UXJZV.js.map +0 -1
- package/dist/internal.d.ts +0 -311
- package/dist/runtime-packages/ui-host-runtime/src/actor-principal.ts +0 -71
- package/dist/runtime-packages/ui-host-runtime/src/browser-interaction.ts +0 -139
- package/dist/runtime-packages/ui-host-runtime/src/components/host-controls.tsx +0 -374
- package/dist/runtime-packages/ui-host-runtime/src/components/host-feedback-toaster.tsx +0 -266
- package/dist/runtime-packages/ui-host-runtime/src/components/host-feedback.tsx +0 -212
- package/dist/runtime-packages/ui-host-runtime/src/components/host-primitives.tsx +0 -271
- package/dist/runtime-packages/ui-host-runtime/src/components/host-session-metadata.tsx +0 -135
- package/dist/runtime-packages/ui-host-runtime/src/components/index.ts +0 -5
- package/dist/runtime-packages/ui-host-runtime/src/components/perf-overlay.tsx +0 -194
- package/dist/runtime-packages/ui-host-runtime/src/gameplay-authority-transport.ts +0 -626
- package/dist/runtime-packages/ui-host-runtime/src/host-controls.tsx +0 -1
- package/dist/runtime-packages/ui-host-runtime/src/host-feedback.tsx +0 -1
- package/dist/runtime-packages/ui-host-runtime/src/host-session-transport.ts +0 -294
- package/dist/runtime-packages/ui-host-runtime/src/index.ts +0 -3
- package/dist/runtime-packages/ui-host-runtime/src/logger.ts +0 -11
- package/dist/runtime-packages/ui-host-runtime/src/perf.ts +0 -324
- package/dist/runtime-packages/ui-host-runtime/src/plugin-bridge.ts +0 -195
- package/dist/runtime-packages/ui-host-runtime/src/plugin-health-check.ts +0 -138
- package/dist/runtime-packages/ui-host-runtime/src/plugin-messages.ts +0 -159
- package/dist/runtime-packages/ui-host-runtime/src/plugin-session-gateway.ts +0 -551
- package/dist/runtime-packages/ui-host-runtime/src/runtime/index.ts +0 -13
- package/dist/runtime-packages/ui-host-runtime/src/screenshot/projection-to-snapshot.ts +0 -122
- package/dist/runtime-packages/ui-host-runtime/src/screenshot/static-store-api.ts +0 -26
- package/dist/runtime-packages/ui-host-runtime/src/session-ingress-controller.ts +0 -583
- package/dist/runtime-packages/ui-host-runtime/src/session-ingress.ts +0 -219
- package/dist/runtime-packages/ui-host-runtime/src/session-live-runtime.ts +0 -117
- package/dist/runtime-packages/ui-host-runtime/src/session-model.ts +0 -431
- package/dist/runtime-packages/ui-host-runtime/src/session-projection.ts +0 -211
- package/dist/runtime-packages/ui-host-runtime/src/session-recovery.ts +0 -80
- package/dist/runtime-packages/ui-host-runtime/src/session-state-reducer.ts +0 -1034
- package/dist/runtime-packages/ui-host-runtime/src/sse-manager.ts +0 -416
- package/dist/runtime-packages/ui-host-runtime/src/unified-session-store.ts +0 -184
- package/dist/testing-KLSV6CPJ.js +0 -674
- package/dist/testing-KLSV6CPJ.js.map +0 -1
- /package/dist/{chunk-2H7UOFLK.js.map → agent-verifier/chunk-SKI2ESE5.mjs.map} +0 -0
- /package/dist/{global-config-AGFBDFYD.js.map → agent-verifier/global-config-Y2NTSK4R.mjs.map} +0 -0
- /package/dist/{keychain-backend-JHTXAKWC.js.map → keychain-backend-HDF4TZDL.js.map} +0 -0
- /package/dist/{prompt-GMZABCJC.js.map → prompt-NDV3AE5L.js.map} +0 -0
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Host-owned inline feedback stack.
|
|
3
|
-
*
|
|
4
|
-
* Visual styling is driven entirely by the active `@dreamboard-games/sdk/ui`
|
|
5
|
-
* `Theme` so the stack re-skins with the rest of the host shell. The
|
|
6
|
-
* earlier implementation relied on raw Tailwind colour classes
|
|
7
|
-
* (`bg-emerald-500/10`, `text-amber-700`, …) which were untouchable
|
|
8
|
-
* by the theme tokens.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { AlertTriangle, Bell, Clock3, X } from "lucide-react";
|
|
12
|
-
import {
|
|
13
|
-
intentForVariant,
|
|
14
|
-
surfaceStyle,
|
|
15
|
-
useTheme,
|
|
16
|
-
type ButtonVariant,
|
|
17
|
-
type Theme,
|
|
18
|
-
} from "@dreamboard-games/sdk/ui";
|
|
19
|
-
import type { HostFeedback } from "../unified-session-store.js";
|
|
20
|
-
|
|
21
|
-
export interface HostFeedbackStackProps {
|
|
22
|
-
feedback: HostFeedback[];
|
|
23
|
-
onDismiss?: (feedbackId: string) => void;
|
|
24
|
-
className?: string;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
interface StackPresentation {
|
|
28
|
-
title: string;
|
|
29
|
-
description: string;
|
|
30
|
-
variant: Extract<ButtonVariant, "danger" | "warning" | "success" | "info">;
|
|
31
|
-
icon: typeof AlertTriangle;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function describeFeedback(item: HostFeedback): StackPresentation {
|
|
35
|
-
switch (item.type) {
|
|
36
|
-
case "YOUR_TURN": {
|
|
37
|
-
const description =
|
|
38
|
-
item.payload.activePlayers.length > 1
|
|
39
|
-
? "You can act with one of your controlled players."
|
|
40
|
-
: "You can act now.";
|
|
41
|
-
return {
|
|
42
|
-
title: "Your turn",
|
|
43
|
-
description,
|
|
44
|
-
variant: "success",
|
|
45
|
-
icon: Bell,
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
case "PROMPT_OPENED": {
|
|
49
|
-
const payload = item.payload;
|
|
50
|
-
const description = payload.targetPlayer
|
|
51
|
-
? `${payload.title ?? "A prompt is waiting."} (${payload.targetPlayer})`
|
|
52
|
-
: (payload.title ?? "A prompt is waiting.");
|
|
53
|
-
return {
|
|
54
|
-
title: "Response needed",
|
|
55
|
-
description,
|
|
56
|
-
variant: "warning",
|
|
57
|
-
icon: Clock3,
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
case "ACTION_REJECTED": {
|
|
61
|
-
const payload = item.payload;
|
|
62
|
-
const description = payload.targetPlayer
|
|
63
|
-
? `${payload.reason} (${payload.targetPlayer})`
|
|
64
|
-
: payload.reason;
|
|
65
|
-
return {
|
|
66
|
-
title: "Action rejected",
|
|
67
|
-
description,
|
|
68
|
-
variant: "danger",
|
|
69
|
-
icon: AlertTriangle,
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const exhaustive: never = item;
|
|
75
|
-
throw new Error(
|
|
76
|
-
`Unsupported host feedback item type: ${String((exhaustive as { type?: unknown }).type)}`,
|
|
77
|
-
);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
interface FeedbackEntryProps {
|
|
81
|
-
item: HostFeedback;
|
|
82
|
-
presentation: StackPresentation;
|
|
83
|
-
theme: Theme;
|
|
84
|
-
onDismiss?: (feedbackId: string) => void;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
function FeedbackEntry({
|
|
88
|
-
item,
|
|
89
|
-
presentation,
|
|
90
|
-
theme,
|
|
91
|
-
onDismiss,
|
|
92
|
-
}: FeedbackEntryProps) {
|
|
93
|
-
const intent = intentForVariant(theme, presentation.variant);
|
|
94
|
-
const Icon = presentation.icon;
|
|
95
|
-
return (
|
|
96
|
-
<div
|
|
97
|
-
role="status"
|
|
98
|
-
aria-live="polite"
|
|
99
|
-
style={{
|
|
100
|
-
...surfaceStyle(theme, { tone: "card", radius: "lg" }),
|
|
101
|
-
background: intent.soft,
|
|
102
|
-
color: intent.onSoft,
|
|
103
|
-
border: `1px solid ${intent.border}`,
|
|
104
|
-
boxShadow: theme.elevation.rest,
|
|
105
|
-
display: "flex",
|
|
106
|
-
alignItems: "flex-start",
|
|
107
|
-
gap: theme.space[3],
|
|
108
|
-
padding: theme.space[3],
|
|
109
|
-
fontFamily: theme.typography.fontFamily.body,
|
|
110
|
-
}}
|
|
111
|
-
>
|
|
112
|
-
<Icon
|
|
113
|
-
size={20}
|
|
114
|
-
strokeWidth={2.5}
|
|
115
|
-
aria-hidden="true"
|
|
116
|
-
style={{
|
|
117
|
-
flexShrink: 0,
|
|
118
|
-
marginTop: 2,
|
|
119
|
-
color: intent.solid,
|
|
120
|
-
}}
|
|
121
|
-
/>
|
|
122
|
-
<div style={{ flex: 1, minWidth: 0 }}>
|
|
123
|
-
<div
|
|
124
|
-
style={{
|
|
125
|
-
fontFamily: theme.typography.fontFamily.display,
|
|
126
|
-
fontSize: theme.typography.fontSize.md,
|
|
127
|
-
fontWeight: theme.typography.fontWeight.bold,
|
|
128
|
-
lineHeight: theme.typography.lineHeight.tight,
|
|
129
|
-
color: intent.onSoft,
|
|
130
|
-
}}
|
|
131
|
-
>
|
|
132
|
-
{presentation.title}
|
|
133
|
-
</div>
|
|
134
|
-
<div
|
|
135
|
-
style={{
|
|
136
|
-
marginTop: theme.space[1],
|
|
137
|
-
fontSize: theme.typography.fontSize.sm,
|
|
138
|
-
fontWeight: theme.typography.fontWeight.medium,
|
|
139
|
-
lineHeight: theme.typography.lineHeight.normal,
|
|
140
|
-
color: intent.onSoft,
|
|
141
|
-
opacity: 0.92,
|
|
142
|
-
wordBreak: "break-word",
|
|
143
|
-
}}
|
|
144
|
-
>
|
|
145
|
-
{presentation.description}
|
|
146
|
-
</div>
|
|
147
|
-
</div>
|
|
148
|
-
{onDismiss ? (
|
|
149
|
-
<button
|
|
150
|
-
type="button"
|
|
151
|
-
aria-label="Dismiss feedback"
|
|
152
|
-
onClick={() => onDismiss(item.id)}
|
|
153
|
-
style={{
|
|
154
|
-
flexShrink: 0,
|
|
155
|
-
width: 28,
|
|
156
|
-
height: 28,
|
|
157
|
-
display: "inline-flex",
|
|
158
|
-
alignItems: "center",
|
|
159
|
-
justifyContent: "center",
|
|
160
|
-
background: "transparent",
|
|
161
|
-
border: "none",
|
|
162
|
-
borderRadius: theme.radius.pill,
|
|
163
|
-
color: intent.onSoft,
|
|
164
|
-
cursor: "pointer",
|
|
165
|
-
opacity: 0.7,
|
|
166
|
-
transition: `opacity ${theme.motion.duration.fast} ${theme.motion.easing.out}`,
|
|
167
|
-
}}
|
|
168
|
-
onMouseEnter={(event) => {
|
|
169
|
-
event.currentTarget.style.opacity = "1";
|
|
170
|
-
}}
|
|
171
|
-
onMouseLeave={(event) => {
|
|
172
|
-
event.currentTarget.style.opacity = "0.7";
|
|
173
|
-
}}
|
|
174
|
-
>
|
|
175
|
-
<X size={16} aria-hidden="true" />
|
|
176
|
-
</button>
|
|
177
|
-
) : null}
|
|
178
|
-
</div>
|
|
179
|
-
);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
export function HostFeedbackStack({
|
|
183
|
-
feedback,
|
|
184
|
-
onDismiss,
|
|
185
|
-
className,
|
|
186
|
-
}: HostFeedbackStackProps) {
|
|
187
|
-
const theme = useTheme();
|
|
188
|
-
if (feedback.length === 0) {
|
|
189
|
-
return null;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
return (
|
|
193
|
-
<div
|
|
194
|
-
className={className}
|
|
195
|
-
style={{
|
|
196
|
-
display: "flex",
|
|
197
|
-
flexDirection: "column",
|
|
198
|
-
gap: theme.space[2],
|
|
199
|
-
}}
|
|
200
|
-
>
|
|
201
|
-
{[...feedback].reverse().map((item) => (
|
|
202
|
-
<FeedbackEntry
|
|
203
|
-
key={item.id}
|
|
204
|
-
item={item}
|
|
205
|
-
presentation={describeFeedback(item)}
|
|
206
|
-
theme={theme}
|
|
207
|
-
onDismiss={onDismiss}
|
|
208
|
-
/>
|
|
209
|
-
))}
|
|
210
|
-
</div>
|
|
211
|
-
);
|
|
212
|
-
}
|
|
@@ -1,271 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
|
|
3
|
-
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
|
4
|
-
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area";
|
|
5
|
-
import { Slot } from "@radix-ui/react-slot";
|
|
6
|
-
import { cva, type VariantProps } from "class-variance-authority";
|
|
7
|
-
import { CircleIcon } from "lucide-react";
|
|
8
|
-
import { clsx, type ClassValue } from "clsx";
|
|
9
|
-
import { twMerge } from "tailwind-merge";
|
|
10
|
-
|
|
11
|
-
export function cn(...inputs: ClassValue[]) {
|
|
12
|
-
return twMerge(clsx(inputs));
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const buttonVariants = cva(
|
|
16
|
-
"inline-flex items-center justify-center gap-2 whitespace-nowrap text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 aria-invalid:border-destructive border-[3px] wobbly-border-md",
|
|
17
|
-
{
|
|
18
|
-
variants: {
|
|
19
|
-
variant: {
|
|
20
|
-
default:
|
|
21
|
-
"border-border hard-shadow hard-shadow-hover hard-shadow-active bg-white text-foreground hover:bg-primary hover:text-white",
|
|
22
|
-
outline:
|
|
23
|
-
"border-border hard-shadow hard-shadow-hover hard-shadow-active bg-transparent hover:bg-muted",
|
|
24
|
-
secondary:
|
|
25
|
-
"border-border hard-shadow hard-shadow-hover hard-shadow-active bg-secondary text-secondary-foreground hover:bg-ring hover:text-white",
|
|
26
|
-
},
|
|
27
|
-
size: {
|
|
28
|
-
default: "h-12 px-6 py-2 has-[>svg]:px-4 text-lg",
|
|
29
|
-
sm: "h-10 gap-1.5 px-4 has-[>svg]:px-3 text-base",
|
|
30
|
-
},
|
|
31
|
-
},
|
|
32
|
-
defaultVariants: {
|
|
33
|
-
variant: "default",
|
|
34
|
-
size: "default",
|
|
35
|
-
},
|
|
36
|
-
},
|
|
37
|
-
);
|
|
38
|
-
|
|
39
|
-
export function Button({
|
|
40
|
-
className,
|
|
41
|
-
variant,
|
|
42
|
-
size,
|
|
43
|
-
asChild = false,
|
|
44
|
-
...props
|
|
45
|
-
}: React.ComponentProps<"button"> &
|
|
46
|
-
VariantProps<typeof buttonVariants> & {
|
|
47
|
-
asChild?: boolean;
|
|
48
|
-
}) {
|
|
49
|
-
const Comp = asChild ? Slot : "button";
|
|
50
|
-
|
|
51
|
-
return (
|
|
52
|
-
<Comp
|
|
53
|
-
data-slot="button"
|
|
54
|
-
className={cn(buttonVariants({ variant, size, className }))}
|
|
55
|
-
{...props}
|
|
56
|
-
/>
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const badgeVariants = cva(
|
|
61
|
-
"inline-flex items-center justify-center rounded-full border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden",
|
|
62
|
-
{
|
|
63
|
-
variants: {
|
|
64
|
-
variant: {
|
|
65
|
-
default:
|
|
66
|
-
"border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
|
|
67
|
-
secondary:
|
|
68
|
-
"border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
|
|
69
|
-
},
|
|
70
|
-
},
|
|
71
|
-
defaultVariants: {
|
|
72
|
-
variant: "default",
|
|
73
|
-
},
|
|
74
|
-
},
|
|
75
|
-
);
|
|
76
|
-
|
|
77
|
-
export function Badge({
|
|
78
|
-
className,
|
|
79
|
-
variant,
|
|
80
|
-
asChild = false,
|
|
81
|
-
...props
|
|
82
|
-
}: React.ComponentProps<"span"> &
|
|
83
|
-
VariantProps<typeof badgeVariants> & { asChild?: boolean }) {
|
|
84
|
-
const Comp = asChild ? Slot : "span";
|
|
85
|
-
|
|
86
|
-
return (
|
|
87
|
-
<Comp
|
|
88
|
-
data-slot="badge"
|
|
89
|
-
className={cn(badgeVariants({ variant }), className)}
|
|
90
|
-
{...props}
|
|
91
|
-
/>
|
|
92
|
-
);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
export function DropdownMenu({
|
|
96
|
-
...props
|
|
97
|
-
}: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {
|
|
98
|
-
return <DropdownMenuPrimitive.Root data-slot="dropdown-menu" {...props} />;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
export function DropdownMenuTrigger({
|
|
102
|
-
...props
|
|
103
|
-
}: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {
|
|
104
|
-
return (
|
|
105
|
-
<DropdownMenuPrimitive.Trigger
|
|
106
|
-
data-slot="dropdown-menu-trigger"
|
|
107
|
-
{...props}
|
|
108
|
-
/>
|
|
109
|
-
);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
export function DropdownMenuContent({
|
|
113
|
-
className,
|
|
114
|
-
sideOffset = 4,
|
|
115
|
-
...props
|
|
116
|
-
}: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) {
|
|
117
|
-
return (
|
|
118
|
-
<DropdownMenuPrimitive.Portal>
|
|
119
|
-
<DropdownMenuPrimitive.Content
|
|
120
|
-
data-slot="dropdown-menu-content"
|
|
121
|
-
sideOffset={sideOffset}
|
|
122
|
-
className={cn(
|
|
123
|
-
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md",
|
|
124
|
-
className,
|
|
125
|
-
)}
|
|
126
|
-
{...props}
|
|
127
|
-
/>
|
|
128
|
-
</DropdownMenuPrimitive.Portal>
|
|
129
|
-
);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
export function DropdownMenuLabel({
|
|
133
|
-
className,
|
|
134
|
-
inset,
|
|
135
|
-
...props
|
|
136
|
-
}: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & {
|
|
137
|
-
inset?: boolean;
|
|
138
|
-
}) {
|
|
139
|
-
return (
|
|
140
|
-
<DropdownMenuPrimitive.Label
|
|
141
|
-
data-slot="dropdown-menu-label"
|
|
142
|
-
data-inset={inset}
|
|
143
|
-
className={cn(
|
|
144
|
-
"px-2 py-1.5 text-sm font-medium data-[inset]:pl-8",
|
|
145
|
-
className,
|
|
146
|
-
)}
|
|
147
|
-
{...props}
|
|
148
|
-
/>
|
|
149
|
-
);
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
export function DropdownMenuRadioGroup({
|
|
153
|
-
...props
|
|
154
|
-
}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) {
|
|
155
|
-
return (
|
|
156
|
-
<DropdownMenuPrimitive.RadioGroup
|
|
157
|
-
data-slot="dropdown-menu-radio-group"
|
|
158
|
-
{...props}
|
|
159
|
-
/>
|
|
160
|
-
);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
export function DropdownMenuRadioItem({
|
|
164
|
-
className,
|
|
165
|
-
children,
|
|
166
|
-
...props
|
|
167
|
-
}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem>) {
|
|
168
|
-
return (
|
|
169
|
-
<DropdownMenuPrimitive.RadioItem
|
|
170
|
-
data-slot="dropdown-menu-radio-item"
|
|
171
|
-
className={cn(
|
|
172
|
-
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
173
|
-
className,
|
|
174
|
-
)}
|
|
175
|
-
{...props}
|
|
176
|
-
>
|
|
177
|
-
<span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
|
|
178
|
-
<DropdownMenuPrimitive.ItemIndicator>
|
|
179
|
-
<CircleIcon className="size-2 fill-current" />
|
|
180
|
-
</DropdownMenuPrimitive.ItemIndicator>
|
|
181
|
-
</span>
|
|
182
|
-
{children}
|
|
183
|
-
</DropdownMenuPrimitive.RadioItem>
|
|
184
|
-
);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
export function DropdownMenuSeparator({
|
|
188
|
-
className,
|
|
189
|
-
...props
|
|
190
|
-
}: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>) {
|
|
191
|
-
return (
|
|
192
|
-
<DropdownMenuPrimitive.Separator
|
|
193
|
-
data-slot="dropdown-menu-separator"
|
|
194
|
-
className={cn("bg-border -mx-1 my-1 h-px", className)}
|
|
195
|
-
{...props}
|
|
196
|
-
/>
|
|
197
|
-
);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
export function Popover({
|
|
201
|
-
...props
|
|
202
|
-
}: React.ComponentProps<typeof PopoverPrimitive.Root>) {
|
|
203
|
-
return <PopoverPrimitive.Root data-slot="popover" {...props} />;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
export function PopoverTrigger({
|
|
207
|
-
...props
|
|
208
|
-
}: React.ComponentProps<typeof PopoverPrimitive.Trigger>) {
|
|
209
|
-
return <PopoverPrimitive.Trigger data-slot="popover-trigger" {...props} />;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
type PopoverContentProps = React.ComponentProps<
|
|
213
|
-
typeof PopoverPrimitive.Content
|
|
214
|
-
> & {
|
|
215
|
-
container?: HTMLElement | null;
|
|
216
|
-
};
|
|
217
|
-
|
|
218
|
-
export function PopoverContent({
|
|
219
|
-
className,
|
|
220
|
-
align = "center",
|
|
221
|
-
sideOffset = 4,
|
|
222
|
-
container,
|
|
223
|
-
...props
|
|
224
|
-
}: PopoverContentProps) {
|
|
225
|
-
return (
|
|
226
|
-
<PopoverPrimitive.Portal container={container ?? undefined}>
|
|
227
|
-
<PopoverPrimitive.Content
|
|
228
|
-
data-slot="popover-content"
|
|
229
|
-
align={align}
|
|
230
|
-
sideOffset={sideOffset}
|
|
231
|
-
className={cn(
|
|
232
|
-
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 origin-(--radix-popover-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden",
|
|
233
|
-
className,
|
|
234
|
-
)}
|
|
235
|
-
{...props}
|
|
236
|
-
/>
|
|
237
|
-
</PopoverPrimitive.Portal>
|
|
238
|
-
);
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
export function ScrollArea({
|
|
242
|
-
className,
|
|
243
|
-
children,
|
|
244
|
-
...props
|
|
245
|
-
}: React.ComponentProps<typeof ScrollAreaPrimitive.Root>) {
|
|
246
|
-
return (
|
|
247
|
-
<ScrollAreaPrimitive.Root
|
|
248
|
-
data-slot="scroll-area"
|
|
249
|
-
className={cn("relative", className)}
|
|
250
|
-
{...props}
|
|
251
|
-
>
|
|
252
|
-
<ScrollAreaPrimitive.Viewport
|
|
253
|
-
data-slot="scroll-area-viewport"
|
|
254
|
-
className="focus-visible:ring-ring/50 size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:outline-1"
|
|
255
|
-
>
|
|
256
|
-
{children}
|
|
257
|
-
</ScrollAreaPrimitive.Viewport>
|
|
258
|
-
<ScrollAreaPrimitive.ScrollAreaScrollbar
|
|
259
|
-
data-slot="scroll-area-scrollbar"
|
|
260
|
-
orientation="vertical"
|
|
261
|
-
className="flex h-full w-2.5 touch-none border-l border-l-transparent p-px transition-colors select-none"
|
|
262
|
-
>
|
|
263
|
-
<ScrollAreaPrimitive.ScrollAreaThumb
|
|
264
|
-
data-slot="scroll-area-thumb"
|
|
265
|
-
className="bg-border relative flex-1 rounded-full"
|
|
266
|
-
/>
|
|
267
|
-
</ScrollAreaPrimitive.ScrollAreaScrollbar>
|
|
268
|
-
<ScrollAreaPrimitive.Corner />
|
|
269
|
-
</ScrollAreaPrimitive.Root>
|
|
270
|
-
);
|
|
271
|
-
}
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
import { useEffect, useState } from "react";
|
|
2
|
-
import { Check, Copy } from "lucide-react";
|
|
3
|
-
|
|
4
|
-
type HostMetaField = "gameId" | "sessionId" | "shortCode";
|
|
5
|
-
|
|
6
|
-
export interface HostSessionMetadataProps {
|
|
7
|
-
gameId: string;
|
|
8
|
-
sessionId: string;
|
|
9
|
-
shortCode: string;
|
|
10
|
-
className?: string;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function HostSessionMetadata({
|
|
14
|
-
gameId,
|
|
15
|
-
sessionId,
|
|
16
|
-
shortCode,
|
|
17
|
-
className,
|
|
18
|
-
}: HostSessionMetadataProps) {
|
|
19
|
-
const [copiedField, setCopiedField] = useState<HostMetaField | null>(null);
|
|
20
|
-
|
|
21
|
-
useEffect(() => {
|
|
22
|
-
if (!copiedField) {
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const timeoutId = window.setTimeout(() => {
|
|
27
|
-
setCopiedField(null);
|
|
28
|
-
}, 1600);
|
|
29
|
-
|
|
30
|
-
return () => {
|
|
31
|
-
window.clearTimeout(timeoutId);
|
|
32
|
-
};
|
|
33
|
-
}, [copiedField]);
|
|
34
|
-
|
|
35
|
-
const handleCopyMeta = async (field: HostMetaField, value: string) => {
|
|
36
|
-
if (!value || !navigator.clipboard?.writeText) {
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
try {
|
|
41
|
-
await navigator.clipboard.writeText(value);
|
|
42
|
-
setCopiedField(field);
|
|
43
|
-
} catch {
|
|
44
|
-
// Ignore clipboard failures; the button remains readable.
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
return (
|
|
49
|
-
<dl className={className ?? "space-y-3 text-sm"}>
|
|
50
|
-
<HostSessionMetaRow
|
|
51
|
-
label="Game ID"
|
|
52
|
-
value={gameId}
|
|
53
|
-
copied={copiedField === "gameId"}
|
|
54
|
-
onCopy={() => void handleCopyMeta("gameId", gameId)}
|
|
55
|
-
truncate
|
|
56
|
-
/>
|
|
57
|
-
<HostSessionMetaRow
|
|
58
|
-
label="Session ID"
|
|
59
|
-
value={sessionId}
|
|
60
|
-
copied={copiedField === "sessionId"}
|
|
61
|
-
onCopy={() => void handleCopyMeta("sessionId", sessionId)}
|
|
62
|
-
truncate
|
|
63
|
-
/>
|
|
64
|
-
<HostSessionMetaRow
|
|
65
|
-
label="Short code"
|
|
66
|
-
value={shortCode}
|
|
67
|
-
copied={copiedField === "shortCode"}
|
|
68
|
-
onCopy={() => void handleCopyMeta("shortCode", shortCode)}
|
|
69
|
-
/>
|
|
70
|
-
</dl>
|
|
71
|
-
);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
interface HostSessionMetaRowProps {
|
|
75
|
-
label: string;
|
|
76
|
-
value: string;
|
|
77
|
-
copied: boolean;
|
|
78
|
-
onCopy: () => void;
|
|
79
|
-
truncate?: boolean;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function HostSessionMetaRow({
|
|
83
|
-
label,
|
|
84
|
-
value,
|
|
85
|
-
copied,
|
|
86
|
-
onCopy,
|
|
87
|
-
truncate = false,
|
|
88
|
-
}: HostSessionMetaRowProps) {
|
|
89
|
-
const displayValue = truncate ? truncateMiddle(value) : value;
|
|
90
|
-
|
|
91
|
-
return (
|
|
92
|
-
<div className="grid grid-cols-[88px_minmax(0,1fr)] items-start gap-3">
|
|
93
|
-
<dt className="pt-0.5 text-[11px] font-bold uppercase tracking-[0.14em] text-muted-foreground">
|
|
94
|
-
{label}
|
|
95
|
-
</dt>
|
|
96
|
-
<dd className="min-w-0">
|
|
97
|
-
<button
|
|
98
|
-
type="button"
|
|
99
|
-
onClick={onCopy}
|
|
100
|
-
className={`flex w-full items-center justify-end gap-2 border-[2px] px-2.5 py-2 text-right transition-all ${
|
|
101
|
-
copied
|
|
102
|
-
? "border-[#2d5da1] bg-[#2d5da1] text-white shadow-[2px_2px_0px_0px_#1d3f72]"
|
|
103
|
-
: "border-border bg-white/85 text-foreground shadow-[2px_2px_0px_0px_#2d2d2d] hover:-translate-y-[1px] hover:bg-[#fff9c4]"
|
|
104
|
-
} wobbly-border-md`}
|
|
105
|
-
title={`Copy ${label}`}
|
|
106
|
-
>
|
|
107
|
-
<span className="min-w-0 flex-1 truncate font-mono text-[12px] font-bold sm:text-[13px]">
|
|
108
|
-
{displayValue}
|
|
109
|
-
</span>
|
|
110
|
-
<span className="inline-flex shrink-0 items-center gap-1 text-[10px] font-bold uppercase tracking-[0.14em]">
|
|
111
|
-
{copied ? (
|
|
112
|
-
<>
|
|
113
|
-
<Check className="h-3.5 w-3.5" />
|
|
114
|
-
Copied
|
|
115
|
-
</>
|
|
116
|
-
) : (
|
|
117
|
-
<>
|
|
118
|
-
<Copy className="h-3.5 w-3.5" />
|
|
119
|
-
Copy
|
|
120
|
-
</>
|
|
121
|
-
)}
|
|
122
|
-
</span>
|
|
123
|
-
</button>
|
|
124
|
-
</dd>
|
|
125
|
-
</div>
|
|
126
|
-
);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function truncateMiddle(value: string, leading = 12, trailing = 8): string {
|
|
130
|
-
if (value.length <= leading + trailing + 3) {
|
|
131
|
-
return value;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
return `${value.slice(0, leading)}...${value.slice(-trailing)}`;
|
|
135
|
-
}
|