@treasuryspatial/prompt-ui-kit 0.1.15 → 0.1.21
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/dist/FeedbackPanel.d.ts +20 -1
- package/dist/FeedbackPanel.d.ts.map +1 -1
- package/dist/FeedbackPanel.js +204 -95
- package/dist/FullscreenImage.d.ts +12 -1
- package/dist/FullscreenImage.d.ts.map +1 -1
- package/dist/FullscreenImage.js +319 -41
- package/dist/GalleryThumbCard.d.ts +2 -1
- package/dist/GalleryThumbCard.d.ts.map +1 -1
- package/dist/GalleryThumbCard.js +121 -3
- package/dist/ImageReferenceStrip.d.ts +9 -0
- package/dist/ImageReferenceStrip.d.ts.map +1 -0
- package/dist/ImageReferenceStrip.js +47 -0
- package/dist/PromptDebugPanel.d.ts +1 -2
- package/dist/PromptDebugPanel.d.ts.map +1 -1
- package/dist/PromptDebugPanel.js +74 -2
- package/dist/RenderHistoryPanel.d.ts +6 -1
- package/dist/RenderHistoryPanel.d.ts.map +1 -1
- package/dist/RenderHistoryPanel.js +55 -55
- package/dist/RenderImageStage.d.ts +10 -0
- package/dist/RenderImageStage.d.ts.map +1 -0
- package/dist/RenderImageStage.js +90 -0
- package/dist/RenderLightboxModal.d.ts +4 -2
- package/dist/RenderLightboxModal.d.ts.map +1 -1
- package/dist/RenderLightboxModal.js +54 -18
- package/dist/RenderPanel.d.ts +17 -16
- package/dist/RenderPanel.d.ts.map +1 -1
- package/dist/RenderPanel.js +178 -204
- package/dist/createRenderHistoryActions.d.ts +11 -0
- package/dist/createRenderHistoryActions.d.ts.map +1 -0
- package/dist/createRenderHistoryActions.js +63 -0
- package/dist/imageDetailPanels.d.ts +14 -0
- package/dist/imageDetailPanels.d.ts.map +1 -0
- package/dist/imageDetailPanels.js +128 -0
- package/dist/index.d.ts +7 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/useRenderImageFlow.d.ts +2 -2
- package/dist/useRenderImageFlow.d.ts.map +1 -1
- package/dist/useRenderImageFlow.js +1 -1
- package/dist/useRenderLightbox.d.ts +14 -2
- package/dist/useRenderLightbox.d.ts.map +1 -1
- package/dist/useRenderLightbox.js +333 -34
- package/package.json +3 -3
package/dist/FeedbackPanel.d.ts
CHANGED
|
@@ -3,7 +3,26 @@ type FeedbackPanelProps = {
|
|
|
3
3
|
page?: string;
|
|
4
4
|
title?: string;
|
|
5
5
|
description?: string;
|
|
6
|
+
roadmap?: FeedbackRoadmapConfig | null;
|
|
6
7
|
};
|
|
7
|
-
|
|
8
|
+
type FeedbackRoadmapItem = {
|
|
9
|
+
id: string;
|
|
10
|
+
name: string;
|
|
11
|
+
description?: string;
|
|
12
|
+
category?: string;
|
|
13
|
+
status?: string;
|
|
14
|
+
enabled?: boolean;
|
|
15
|
+
sortOrder?: number;
|
|
16
|
+
rank?: number;
|
|
17
|
+
score?: number;
|
|
18
|
+
};
|
|
19
|
+
type FeedbackRoadmapConfig = {
|
|
20
|
+
enabled?: boolean;
|
|
21
|
+
title?: string;
|
|
22
|
+
description?: string;
|
|
23
|
+
rankingMode?: string;
|
|
24
|
+
items?: FeedbackRoadmapItem[];
|
|
25
|
+
};
|
|
26
|
+
export default function FeedbackPanel({ toolId, page, title, description, roadmap, }: FeedbackPanelProps): import("react/jsx-runtime").JSX.Element;
|
|
8
27
|
export {};
|
|
9
28
|
//# sourceMappingURL=FeedbackPanel.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FeedbackPanel.d.ts","sourceRoot":"","sources":["../src/FeedbackPanel.tsx"],"names":[],"mappings":"AAKA,KAAK,kBAAkB,GAAG;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"FeedbackPanel.d.ts","sourceRoot":"","sources":["../src/FeedbackPanel.tsx"],"names":[],"mappings":"AAKA,KAAK,kBAAkB,GAAG;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,qBAAqB,GAAG,IAAI,CAAC;CACxC,CAAC;AAEF,KAAK,mBAAmB,GAAG;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,KAAK,qBAAqB,GAAG;IAC3B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,mBAAmB,EAAE,CAAC;CAC/B,CAAC;AAyIF,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,EACpC,MAAW,EACX,IAAS,EACT,KAAoC,EACpC,WAAwH,EACxH,OAAc,GACf,EAAE,kBAAkB,2CAuSpB"}
|
package/dist/FeedbackPanel.js
CHANGED
|
@@ -1,64 +1,40 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useRef, useState } from 'react';
|
|
3
|
+
import { useEffect, useRef, useState } from 'react';
|
|
4
4
|
import styled from 'styled-components';
|
|
5
5
|
const FEEDBACK_IMAGE_LIMIT = 3;
|
|
6
6
|
const FEEDBACK_IMAGE_MAX_BYTES = 5 * 1024 * 1024;
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
gap: 16px;
|
|
11
|
-
`;
|
|
12
|
-
const Header = styled.div `
|
|
13
|
-
display: flex;
|
|
14
|
-
flex-direction: column;
|
|
15
|
-
gap: 6px;
|
|
16
|
-
`;
|
|
17
|
-
const Title = styled.div `
|
|
18
|
-
font-size: 17px;
|
|
19
|
-
font-weight: 600;
|
|
20
|
-
letter-spacing: 0.01em;
|
|
21
|
-
color: var(--brand-text-primary);
|
|
7
|
+
const TELEMETRY_SESSION_STORAGE_KEY = 'telemetry:session-id';
|
|
8
|
+
const Root = styled.div.attrs({ className: 'viewer-ui-panel-sections' }) `
|
|
9
|
+
font-family: var(--viewer-ui-font-body, var(--ui-font-family, 'Aenik', 'Aeonik', system-ui, sans-serif));
|
|
22
10
|
`;
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
11
|
+
const Section = styled.section.attrs({ className: 'panel-section' }) ``;
|
|
12
|
+
const SectionHeader = styled.div.attrs({ className: 'panel-section-header' }) ``;
|
|
13
|
+
const SectionHeaderCopy = styled.div `
|
|
14
|
+
min-width: 0;
|
|
27
15
|
`;
|
|
28
|
-
const
|
|
16
|
+
const SectionFields = styled.div.attrs({ className: 'panel-section-fields' }) ``;
|
|
17
|
+
const Textarea = styled.textarea.attrs({ className: 'cfg-textarea' }) `
|
|
29
18
|
width: 100%;
|
|
30
|
-
min-height:
|
|
19
|
+
min-height: 136px;
|
|
31
20
|
resize: vertical;
|
|
32
|
-
|
|
33
|
-
border: 1px solid var(--brand-text-primary);
|
|
34
|
-
background: var(--brand-background);
|
|
35
|
-
padding: 18px 20px;
|
|
36
|
-
font-size: 13px;
|
|
37
|
-
line-height: 1.6;
|
|
38
|
-
color: var(--brand-text-primary);
|
|
39
|
-
outline: none;
|
|
21
|
+
font-family: var(--viewer-ui-font-body, var(--ui-font-family, 'Aenik', 'Aeonik', system-ui, sans-serif));
|
|
40
22
|
|
|
41
23
|
&::placeholder {
|
|
24
|
+
font-family: var(--viewer-ui-font-body, var(--ui-font-family, 'Aenik', 'Aeonik', system-ui, sans-serif));
|
|
25
|
+
letter-spacing: 0;
|
|
42
26
|
color: color-mix(in srgb, var(--brand-text-secondary) 72%, white 28%);
|
|
43
27
|
}
|
|
44
|
-
|
|
45
|
-
&:focus {
|
|
46
|
-
border-color: var(--brand-primary);
|
|
47
|
-
}
|
|
48
|
-
`;
|
|
49
|
-
const Note = styled.div `
|
|
50
|
-
font-size: 12px;
|
|
51
|
-
line-height: 1.5;
|
|
52
|
-
color: var(--brand-text-secondary);
|
|
53
28
|
`;
|
|
29
|
+
const Note = styled.div.attrs({ className: 'panel-section-note' }) ``;
|
|
54
30
|
const DropZone = styled.div `
|
|
55
|
-
margin-top:
|
|
56
|
-
border-radius:
|
|
57
|
-
border:
|
|
31
|
+
margin-top: 8px;
|
|
32
|
+
border-radius: 18px;
|
|
33
|
+
border: 1px dashed ${(props) => (props.$dragActive ? 'var(--brand-primary)' : 'var(--brand-panel-border)')};
|
|
58
34
|
background: ${(props) => props.$dragActive
|
|
59
35
|
? 'color-mix(in srgb, var(--brand-primary) 10%, var(--brand-background) 90%)'
|
|
60
36
|
: 'var(--brand-background)'};
|
|
61
|
-
padding:
|
|
37
|
+
padding: 18px 14px;
|
|
62
38
|
text-align: center;
|
|
63
39
|
transition: border-color 0.16s ease, background-color 0.16s ease;
|
|
64
40
|
`;
|
|
@@ -67,26 +43,28 @@ const DropButton = styled.button `
|
|
|
67
43
|
background: transparent;
|
|
68
44
|
color: var(--brand-text-primary);
|
|
69
45
|
cursor: pointer;
|
|
70
|
-
font-
|
|
46
|
+
font-family: inherit;
|
|
47
|
+
font-size: 11px;
|
|
71
48
|
font-weight: 600;
|
|
72
|
-
letter-spacing: 0.
|
|
49
|
+
letter-spacing: 0.08em;
|
|
50
|
+
text-transform: var(--viewer-ui-action-text-case, lowercase);
|
|
73
51
|
`;
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
52
|
+
const HiddenFileInput = styled.input `
|
|
53
|
+
position: absolute;
|
|
54
|
+
width: 1px;
|
|
55
|
+
height: 1px;
|
|
56
|
+
padding: 0;
|
|
57
|
+
margin: -1px;
|
|
58
|
+
overflow: hidden;
|
|
59
|
+
clip: rect(0 0 0 0);
|
|
60
|
+
white-space: nowrap;
|
|
61
|
+
border: 0;
|
|
62
|
+
`;
|
|
63
|
+
const FileList = styled.div.attrs({ className: 'panel-section-list' }) `
|
|
78
64
|
margin-top: 10px;
|
|
79
65
|
`;
|
|
80
|
-
const FileRow = styled.div `
|
|
81
|
-
|
|
82
|
-
align-items: center;
|
|
83
|
-
justify-content: space-between;
|
|
84
|
-
gap: 12px;
|
|
85
|
-
border-radius: 18px;
|
|
86
|
-
border: 1px solid var(--brand-panel-border);
|
|
87
|
-
background: var(--brand-background);
|
|
88
|
-
padding: 12px 14px;
|
|
89
|
-
font-size: 12px;
|
|
66
|
+
const FileRow = styled.div.attrs({ className: 'panel-section-row' }) `
|
|
67
|
+
font-size: 11px;
|
|
90
68
|
color: var(--brand-text-secondary);
|
|
91
69
|
`;
|
|
92
70
|
const RemoveButton = styled.button `
|
|
@@ -102,32 +80,95 @@ const Status = styled.div `
|
|
|
102
80
|
font-size: 12px;
|
|
103
81
|
color: ${(props) => props.$tone === 'success' ? 'var(--brand-text-primary)' : 'var(--viewer-ui-color-text-error, #b91c1c)'};
|
|
104
82
|
`;
|
|
105
|
-
const SubmitButton = styled.button `
|
|
83
|
+
const SubmitButton = styled.button.attrs({ className: 'cfg-button cfg-button--primary' }) `
|
|
106
84
|
width: 100%;
|
|
107
|
-
|
|
85
|
+
font-family: inherit;
|
|
86
|
+
`;
|
|
87
|
+
const RoadmapSection = styled.section.attrs({ className: 'panel-section' }) ``;
|
|
88
|
+
const RoadmapList = styled.div.attrs({ className: 'panel-section-stack' }) ``;
|
|
89
|
+
const RoadmapItem = styled.div.attrs({ className: 'panel-section-group' }) ``;
|
|
90
|
+
const RoadmapItemHeader = styled.div `
|
|
91
|
+
display: flex;
|
|
92
|
+
align-items: flex-start;
|
|
93
|
+
justify-content: space-between;
|
|
94
|
+
gap: 12px;
|
|
95
|
+
`;
|
|
96
|
+
const RoadmapItemTitle = styled.h4 ``;
|
|
97
|
+
const RoadmapItemDescription = styled.p ``;
|
|
98
|
+
const RoadmapMeta = styled.div.attrs({ className: 'panel-chip-row' }) ``;
|
|
99
|
+
const RoadmapTag = styled.span `
|
|
108
100
|
border-radius: 999px;
|
|
109
|
-
border:
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
letter-spacing: 0.
|
|
116
|
-
transition: opacity 0.16s ease;
|
|
117
|
-
|
|
118
|
-
&:disabled {
|
|
119
|
-
opacity: 0.5;
|
|
120
|
-
cursor: not-allowed;
|
|
121
|
-
}
|
|
101
|
+
border: 1px solid var(--brand-panel-border);
|
|
102
|
+
padding: 3px 8px;
|
|
103
|
+
font-size: 9px;
|
|
104
|
+
line-height: 1;
|
|
105
|
+
color: var(--brand-text-secondary);
|
|
106
|
+
text-transform: uppercase;
|
|
107
|
+
letter-spacing: 0.1em;
|
|
122
108
|
`;
|
|
123
|
-
|
|
109
|
+
const VoteButton = styled.button.attrs({ className: 'cfg-button cfg-button--secondary cfg-button--compact' }) `
|
|
110
|
+
flex: 0 0 auto;
|
|
111
|
+
font-family: inherit;
|
|
112
|
+
`;
|
|
113
|
+
export default function FeedbackPanel({ toolId = '', page = '', title = 'design requests + feedback', description = 'Request new design types, plugins, tools, workflows, features, bug fixes, or visual/render improvements.', roadmap = null, }) {
|
|
124
114
|
const [message, setMessage] = useState('');
|
|
125
115
|
const [status, setStatus] = useState('idle');
|
|
126
116
|
const [error, setError] = useState('');
|
|
127
117
|
const [images, setImages] = useState([]);
|
|
128
118
|
const [imageError, setImageError] = useState('');
|
|
129
119
|
const [dragActive, setDragActive] = useState(false);
|
|
120
|
+
const [roadmapItems, setRoadmapItems] = useState([]);
|
|
121
|
+
const [roadmapStatus, setRoadmapStatus] = useState('idle');
|
|
122
|
+
const [roadmapError, setRoadmapError] = useState('');
|
|
123
|
+
const [votedFeatureIds, setVotedFeatureIds] = useState(() => new Set());
|
|
130
124
|
const inputRef = useRef(null);
|
|
125
|
+
const configuredRoadmapItems = (roadmap?.items ?? [])
|
|
126
|
+
.filter((item) => item && item.enabled !== false && item.id && item.name)
|
|
127
|
+
.sort((a, b) => {
|
|
128
|
+
const aOrder = Number.isFinite(Number(a.sortOrder)) ? Number(a.sortOrder) : 9999;
|
|
129
|
+
const bOrder = Number.isFinite(Number(b.sortOrder)) ? Number(b.sortOrder) : 9999;
|
|
130
|
+
return aOrder - bOrder || a.name.localeCompare(b.name);
|
|
131
|
+
});
|
|
132
|
+
const visibleRoadmapItems = roadmapItems.length > 0 ? roadmapItems : configuredRoadmapItems;
|
|
133
|
+
useEffect(() => {
|
|
134
|
+
if (roadmap?.enabled === false || configuredRoadmapItems.length === 0) {
|
|
135
|
+
setRoadmapItems([]);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
let cancelled = false;
|
|
139
|
+
const loadRoadmap = async () => {
|
|
140
|
+
setRoadmapStatus('loading');
|
|
141
|
+
setRoadmapError('');
|
|
142
|
+
try {
|
|
143
|
+
const response = await fetch('/api/feedback/roadmap', { cache: 'no-store' });
|
|
144
|
+
const payload = await response.json().catch(() => null);
|
|
145
|
+
if (!response.ok || !payload?.success) {
|
|
146
|
+
throw new Error(payload?.error || 'Failed to load roadmap ranking');
|
|
147
|
+
}
|
|
148
|
+
if (cancelled)
|
|
149
|
+
return;
|
|
150
|
+
const rankedItems = Array.isArray(payload?.data?.items) ? payload.data.items : payload?.items;
|
|
151
|
+
if (Array.isArray(rankedItems) && rankedItems.length > 0) {
|
|
152
|
+
setRoadmapItems(rankedItems.filter((item) => item?.enabled !== false && item?.id && item?.name));
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
setRoadmapItems([]);
|
|
156
|
+
}
|
|
157
|
+
setRoadmapStatus('idle');
|
|
158
|
+
}
|
|
159
|
+
catch (nextError) {
|
|
160
|
+
if (cancelled)
|
|
161
|
+
return;
|
|
162
|
+
setRoadmapItems([]);
|
|
163
|
+
setRoadmapError(nextError?.message || 'Failed to load roadmap ranking');
|
|
164
|
+
setRoadmapStatus('error');
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
void loadRoadmap();
|
|
168
|
+
return () => {
|
|
169
|
+
cancelled = true;
|
|
170
|
+
};
|
|
171
|
+
}, [roadmap?.enabled, configuredRoadmapItems.map((item) => item.id).join('|')]);
|
|
131
172
|
const addFiles = (fileList) => {
|
|
132
173
|
const incoming = Array.from(fileList);
|
|
133
174
|
const remaining = Math.max(0, FEEDBACK_IMAGE_LIMIT - images.length);
|
|
@@ -149,6 +190,55 @@ export default function FeedbackPanel({ toolId = '', page = '', title = 'feedbac
|
|
|
149
190
|
]);
|
|
150
191
|
};
|
|
151
192
|
const removeFile = (id) => setImages((prev) => prev.filter((item) => item.id !== id));
|
|
193
|
+
const voteForRoadmapItem = async (featureId) => {
|
|
194
|
+
setRoadmapStatus('voting');
|
|
195
|
+
setRoadmapError('');
|
|
196
|
+
try {
|
|
197
|
+
const submissionId = (typeof crypto !== 'undefined' && 'randomUUID' in crypto && crypto.randomUUID()) ||
|
|
198
|
+
`${Date.now()}-${Math.random().toString(16).slice(2, 10)}`;
|
|
199
|
+
let telemetrySessionId = '';
|
|
200
|
+
try {
|
|
201
|
+
telemetrySessionId = window.sessionStorage.getItem(TELEMETRY_SESSION_STORAGE_KEY) || '';
|
|
202
|
+
}
|
|
203
|
+
catch {
|
|
204
|
+
telemetrySessionId = '';
|
|
205
|
+
}
|
|
206
|
+
const response = await fetch('/api/feedback/roadmap', {
|
|
207
|
+
method: 'POST',
|
|
208
|
+
headers: {
|
|
209
|
+
'Content-Type': 'application/json',
|
|
210
|
+
'x-submission-id': submissionId,
|
|
211
|
+
},
|
|
212
|
+
body: JSON.stringify({
|
|
213
|
+
featureId,
|
|
214
|
+
submissionId,
|
|
215
|
+
telemetrySessionId,
|
|
216
|
+
toolId,
|
|
217
|
+
page,
|
|
218
|
+
}),
|
|
219
|
+
});
|
|
220
|
+
const payload = await response.json().catch(() => null);
|
|
221
|
+
if (!response.ok || !payload?.success) {
|
|
222
|
+
throw new Error(payload?.error || 'Failed to record roadmap vote');
|
|
223
|
+
}
|
|
224
|
+
setVotedFeatureIds((current) => {
|
|
225
|
+
const next = new Set(current);
|
|
226
|
+
next.add(featureId);
|
|
227
|
+
return next;
|
|
228
|
+
});
|
|
229
|
+
setRoadmapStatus('idle');
|
|
230
|
+
const reload = await fetch('/api/feedback/roadmap', { cache: 'no-store' });
|
|
231
|
+
const nextPayload = await reload.json().catch(() => null);
|
|
232
|
+
const rankedItems = Array.isArray(nextPayload?.data?.items) ? nextPayload.data.items : nextPayload?.items;
|
|
233
|
+
if (reload.ok && Array.isArray(rankedItems)) {
|
|
234
|
+
setRoadmapItems(rankedItems.filter((item) => item?.enabled !== false && item?.id && item?.name));
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
catch (nextError) {
|
|
238
|
+
setRoadmapStatus('error');
|
|
239
|
+
setRoadmapError(nextError?.message || 'Failed to record roadmap vote');
|
|
240
|
+
}
|
|
241
|
+
};
|
|
152
242
|
const submit = async () => {
|
|
153
243
|
const trimmed = message.trim();
|
|
154
244
|
if (!trimmed) {
|
|
@@ -160,13 +250,29 @@ export default function FeedbackPanel({ toolId = '', page = '', title = 'feedbac
|
|
|
160
250
|
setError('');
|
|
161
251
|
try {
|
|
162
252
|
const form = new FormData();
|
|
253
|
+
const submissionId = (typeof crypto !== 'undefined' && 'randomUUID' in crypto && crypto.randomUUID()) ||
|
|
254
|
+
`${Date.now()}-${Math.random().toString(16).slice(2, 10)}`;
|
|
163
255
|
form.set('message', trimmed);
|
|
256
|
+
form.set('submissionId', submissionId);
|
|
257
|
+
form.set('category', 'design-type-feature-feedback');
|
|
164
258
|
if (toolId)
|
|
165
259
|
form.set('toolId', toolId);
|
|
166
260
|
if (page)
|
|
167
261
|
form.set('page', page);
|
|
262
|
+
try {
|
|
263
|
+
const telemetrySessionId = window.sessionStorage.getItem(TELEMETRY_SESSION_STORAGE_KEY);
|
|
264
|
+
if (telemetrySessionId)
|
|
265
|
+
form.set('telemetrySessionId', telemetrySessionId);
|
|
266
|
+
}
|
|
267
|
+
catch {
|
|
268
|
+
// Ignore storage failures; the server still writes feedback.
|
|
269
|
+
}
|
|
168
270
|
images.forEach((item) => form.append('images', item.file));
|
|
169
|
-
const response = await fetch('/api/feedback', {
|
|
271
|
+
const response = await fetch('/api/feedback', {
|
|
272
|
+
method: 'POST',
|
|
273
|
+
body: form,
|
|
274
|
+
headers: { 'x-submission-id': submissionId },
|
|
275
|
+
});
|
|
170
276
|
const payload = await response.json().catch(() => null);
|
|
171
277
|
if (!response.ok || !payload?.success)
|
|
172
278
|
throw new Error(payload?.error || 'Failed to send feedback');
|
|
@@ -179,24 +285,27 @@ export default function FeedbackPanel({ toolId = '', page = '', title = 'feedbac
|
|
|
179
285
|
setError(nextError?.message || 'Failed to send feedback');
|
|
180
286
|
}
|
|
181
287
|
};
|
|
182
|
-
return (_jsxs(Root, { children: [_jsxs(
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
}
|
|
188
|
-
}, rows: 6, placeholder: "Share feedback, feature requests, or issues." }), _jsxs("div", { children: [_jsxs(Note, { children: ["Add up to ", FEEDBACK_IMAGE_LIMIT, " screenshots (max ", Math.round(FEEDBACK_IMAGE_MAX_BYTES / 1024 / 1024), "MB each)."] }), _jsxs(DropZone, { "$dragActive": dragActive, onDragOver: (event) => {
|
|
189
|
-
event.preventDefault();
|
|
190
|
-
setDragActive(true);
|
|
191
|
-
}, onDragLeave: () => setDragActive(false), onDrop: (event) => {
|
|
192
|
-
event.preventDefault();
|
|
193
|
-
setDragActive(false);
|
|
194
|
-
if (event.dataTransfer?.files?.length)
|
|
195
|
-
addFiles(event.dataTransfer.files);
|
|
196
|
-
}, children: [_jsx("input", { ref: inputRef, type: "file", accept: "image/*", multiple: true, className: "hidden", onChange: (event) => {
|
|
197
|
-
if (event.target.files?.length) {
|
|
198
|
-
addFiles(event.target.files);
|
|
199
|
-
event.target.value = '';
|
|
288
|
+
return (_jsxs(Root, { children: [_jsxs(Section, { "data-panel-id": "feedback-request", children: [_jsx(SectionHeader, { children: _jsxs(SectionHeaderCopy, { children: [_jsx("h3", { children: title }), _jsx("p", { children: description })] }) }), _jsxs(SectionFields, { children: [_jsx(Textarea, { value: message, onChange: (event) => {
|
|
289
|
+
setMessage(event.target.value);
|
|
290
|
+
if (status !== 'idle') {
|
|
291
|
+
setStatus('idle');
|
|
292
|
+
setError('');
|
|
200
293
|
}
|
|
201
|
-
}
|
|
294
|
+
}, rows: 6, placeholder: "Ask for a new design type, plugin, workflow, feature, or fix. Include what you want to make and what output should change." }), _jsxs("div", { children: [_jsxs(Note, { children: ["Add up to ", FEEDBACK_IMAGE_LIMIT, " screenshots (max ", Math.round(FEEDBACK_IMAGE_MAX_BYTES / 1024 / 1024), "MB each)."] }), _jsxs(DropZone, { "$dragActive": dragActive, onDragOver: (event) => {
|
|
295
|
+
event.preventDefault();
|
|
296
|
+
setDragActive(true);
|
|
297
|
+
}, onDragLeave: () => setDragActive(false), onDrop: (event) => {
|
|
298
|
+
event.preventDefault();
|
|
299
|
+
setDragActive(false);
|
|
300
|
+
if (event.dataTransfer?.files?.length)
|
|
301
|
+
addFiles(event.dataTransfer.files);
|
|
302
|
+
}, children: [_jsx(HiddenFileInput, { ref: inputRef, type: "file", accept: "image/*", multiple: true, onChange: (event) => {
|
|
303
|
+
if (event.target.files?.length) {
|
|
304
|
+
addFiles(event.target.files);
|
|
305
|
+
event.target.value = '';
|
|
306
|
+
}
|
|
307
|
+
} }), _jsx(DropButton, { type: "button", onClick: () => inputRef.current?.click(), children: "drop screenshots here or click to upload" })] }), imageError ? _jsx(Status, { "$tone": "error", style: { marginTop: '8px' }, children: imageError }) : null, images.length > 0 ? (_jsx(FileList, { children: images.map((item) => (_jsxs(FileRow, { children: [_jsx("span", { className: "truncate", children: item.file.name }), _jsx(RemoveButton, { type: "button", onClick: () => removeFile(item.id), children: "remove" })] }, item.id))) })) : null] }), status === 'error' ? _jsx(Status, { "$tone": "error", children: error || 'Failed to send feedback.' }) : null, status === 'success' ? _jsx(Status, { "$tone": "success", children: "Thanks \u2014 we received your feedback." }) : null, _jsx(SubmitButton, { type: "button", onClick: () => void submit(), disabled: status === 'sending', children: status === 'sending' ? 'sending...' : 'send request' })] })] }), roadmap?.enabled !== false && visibleRoadmapItems.length > 0 ? (_jsxs(RoadmapSection, { "data-panel-id": "feedback-roadmap", children: [_jsx(SectionHeader, { children: _jsxs(SectionHeaderCopy, { children: [_jsx("h3", { children: roadmap?.title || 'roadmap priorities' }), roadmap?.description ? _jsx("p", { children: roadmap.description }) : null] }) }), roadmapStatus === 'error' && roadmapError ? _jsx(Status, { "$tone": "error", children: roadmapError }) : null, _jsx(RoadmapList, { children: visibleRoadmapItems.map((item) => {
|
|
308
|
+
const voted = votedFeatureIds.has(item.id);
|
|
309
|
+
return (_jsxs(RoadmapItem, { children: [_jsxs(RoadmapItemHeader, { children: [_jsxs("div", { children: [_jsx(RoadmapItemTitle, { children: item.name }), item.description ? _jsx(RoadmapItemDescription, { children: item.description }) : null] }), _jsx(VoteButton, { type: "button", onClick: () => void voteForRoadmapItem(item.id), disabled: roadmapStatus === 'voting' || voted, children: voted ? 'noted' : 'vote' })] }), item.category || item.status ? (_jsxs(RoadmapMeta, { children: [item.category ? _jsx(RoadmapTag, { children: item.category }) : null, item.status ? _jsx(RoadmapTag, { children: item.status }) : null] })) : null] }, item.id));
|
|
310
|
+
}) })] })) : null] }));
|
|
202
311
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
1
2
|
type ActionConfig = {
|
|
2
3
|
label: string;
|
|
3
4
|
onClick?: () => void;
|
|
@@ -11,6 +12,13 @@ type EditableTitleConfig = {
|
|
|
11
12
|
onSave: () => void;
|
|
12
13
|
status?: 'idle' | 'saving' | 'saved' | 'error';
|
|
13
14
|
};
|
|
15
|
+
export type FullscreenDetailPanelConfig = {
|
|
16
|
+
id: string;
|
|
17
|
+
label: string;
|
|
18
|
+
description?: string;
|
|
19
|
+
content: ReactNode;
|
|
20
|
+
defaultOpen?: boolean;
|
|
21
|
+
};
|
|
14
22
|
type FullscreenImageProps = {
|
|
15
23
|
open: boolean;
|
|
16
24
|
src: string;
|
|
@@ -26,8 +34,11 @@ type FullscreenImageProps = {
|
|
|
26
34
|
onClose: () => void;
|
|
27
35
|
primaryAction?: ActionConfig | null;
|
|
28
36
|
secondaryAction?: ActionConfig | null;
|
|
37
|
+
extraActions?: ActionConfig[];
|
|
29
38
|
editableTitle?: EditableTitleConfig | null;
|
|
39
|
+
detailPanels?: FullscreenDetailPanelConfig[];
|
|
40
|
+
statusText?: string | null;
|
|
30
41
|
};
|
|
31
|
-
export default function FullscreenImage({ open, src, alt, title, subtitle, modeLabel,
|
|
42
|
+
export default function FullscreenImage({ open, src, alt, title, subtitle, modeLabel, createdAt, publicUrl, copyUrl, onClose, primaryAction, secondaryAction, extraActions, editableTitle, detailPanels, statusText, }: FullscreenImageProps): import("react/jsx-runtime").JSX.Element | null;
|
|
32
43
|
export {};
|
|
33
44
|
//# sourceMappingURL=FullscreenImage.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FullscreenImage.d.ts","sourceRoot":"","sources":["../src/FullscreenImage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"FullscreenImage.d.ts","sourceRoot":"","sources":["../src/FullscreenImage.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAgC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAGrE,KAAK,YAAY,GAAG;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;IACpE,OAAO,CAAC,EAAE,SAAS,GAAG,WAAW,CAAC;CACnC,CAAC;AAEF,KAAK,mBAAmB,GAAG;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,GAAG,OAAO,CAAC;CAChD,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,SAAS,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF,KAAK,oBAAoB,GAAG;IAC1B,IAAI,EAAE,OAAO,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,aAAa,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;IACpC,eAAe,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;IACtC,YAAY,CAAC,EAAE,YAAY,EAAE,CAAC;IAC9B,aAAa,CAAC,EAAE,mBAAmB,GAAG,IAAI,CAAC;IAC3C,YAAY,CAAC,EAAE,2BAA2B,EAAE,CAAC;IAC7C,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B,CAAC;AAoRF,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,EACtC,IAAI,EACJ,GAAG,EACH,GAAa,EACb,KAAK,EACL,QAAQ,EACR,SAAS,EACT,SAAS,EACT,SAAS,EACT,OAAO,EACP,OAAO,EACP,aAAa,EACb,eAAe,EACf,YAAiB,EACjB,aAAa,EACb,YAAiB,EACjB,UAAU,GACX,EAAE,oBAAoB,kDAiNtB"}
|