@striae-org/striae 3.0.4 → 3.1.0
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/NOTICE +0 -5
- package/app/components/actions/case-export/core-export.ts +1 -1
- package/app/components/actions/case-export/download-handlers.ts +10 -12
- package/app/components/actions/case-export/metadata-helpers.ts +1 -1
- package/app/components/actions/case-import/confirmation-import.ts +24 -9
- package/app/components/actions/case-import/orchestrator.ts +3 -4
- package/app/components/actions/case-import/validation.ts +3 -3
- package/app/components/actions/case-import/zip-processing.ts +12 -48
- package/app/components/actions/case-manage.ts +0 -1
- package/app/components/actions/confirm-export.ts +2 -2
- package/app/components/audit/user-audit-viewer.tsx +53 -15
- package/app/components/audit/user-audit.module.css +11 -4
- package/app/components/canvas/box-annotations/box-annotations.tsx +36 -7
- package/app/components/canvas/canvas.tsx +35 -24
- package/app/components/canvas/confirmation/confirmation.module.css +5 -2
- package/app/components/canvas/confirmation/confirmation.tsx +25 -8
- package/app/components/sidebar/case-export/case-export.module.css +194 -5
- package/app/components/sidebar/case-export/case-export.tsx +291 -11
- package/app/components/sidebar/case-import/case-import.module.css +9 -5
- package/app/components/sidebar/case-import/case-import.tsx +30 -7
- package/app/components/sidebar/case-import/components/CasePreviewSection.tsx +2 -2
- package/app/components/sidebar/case-import/components/ConfirmationDialog.tsx +1 -1
- package/app/components/sidebar/case-import/components/ExistingCaseSection.tsx +1 -1
- package/app/components/sidebar/case-import/hooks/useFilePreview.ts +34 -9
- package/app/components/sidebar/cases/case-sidebar.tsx +13 -13
- package/app/components/sidebar/cases/cases-modal.tsx +12 -2
- package/app/components/sidebar/files/files-modal.tsx +28 -8
- package/app/components/sidebar/sidebar.module.css +2 -3
- package/app/components/sidebar/sidebar.tsx +1 -16
- package/app/components/sidebar/upload/image-upload-zone.tsx +4 -4
- package/app/components/toolbar/toolbar-color-selector.module.css +2 -2
- package/app/components/toolbar/toolbar-color-selector.tsx +3 -3
- package/app/components/toolbar/toolbar.tsx +19 -9
- package/app/components/user/delete-account.module.css +4 -1
- package/app/components/user/delete-account.tsx +22 -3
- package/app/components/user/manage-profile.tsx +0 -2
- package/app/entry.server.tsx +2 -3
- package/app/hooks/useInactivityTimeout.ts +5 -1
- package/app/root.tsx +0 -3
- package/app/routes/_index.tsx +1 -16
- package/app/routes/auth/emailVerification.tsx +1 -1
- package/app/routes/auth/login.tsx +7 -5
- package/app/routes/auth/route.ts +3 -12
- package/app/routes/striae/striae.tsx +1 -1
- package/app/services/audit.service.ts +29 -9
- package/app/tailwind.css +16 -1
- package/app/types/audit.ts +3 -3
- package/app/types/case.ts +1 -1
- package/app/types/import.ts +0 -2
- package/app/utils/SHA256.ts +3 -3
- package/app/utils/batch-operations.ts +6 -6
- package/app/utils/data-operations.ts +14 -7
- package/app/utils/permissions.ts +0 -2
- package/functions/[[path]].ts +0 -1
- package/package.json +1 -2
- package/public/_headers +0 -12
- package/public/assets/striae.jpg +0 -0
- package/scripts/deploy-config.sh +0 -7
- package/scripts/run-eslint.cjs +14 -6
- package/worker-configuration.d.ts +2 -2
- package/workers/audit-worker/src/audit-worker.example.ts +9 -7
- package/workers/audit-worker/worker-configuration.d.ts +2 -2
- package/workers/audit-worker/wrangler.jsonc.example +1 -1
- package/workers/data-worker/src/data-worker.example.ts +1 -1
- package/workers/data-worker/worker-configuration.d.ts +2 -2
- package/workers/data-worker/wrangler.jsonc.example +1 -1
- package/workers/image-worker/worker-configuration.d.ts +2 -2
- package/workers/image-worker/wrangler.jsonc.example +1 -1
- package/workers/keys-worker/worker-configuration.d.ts +2 -2
- package/workers/keys-worker/wrangler.jsonc.example +1 -1
- package/workers/pdf-worker/src/pdf-worker.example.ts +3 -3
- package/workers/pdf-worker/worker-configuration.d.ts +7448 -7448
- package/workers/pdf-worker/wrangler.jsonc.example +1 -1
- package/workers/user-worker/src/user-worker.example.ts +10 -10
- package/workers/user-worker/worker-configuration.d.ts +2 -2
- package/workers/user-worker/wrangler.jsonc.example +1 -1
- package/wrangler.toml.example +1 -1
- package/app/components/sidebar/hash/hash-utility.module.css +0 -366
- package/app/components/sidebar/hash/hash-utility.tsx +0 -982
- package/app/config-example/meta-config.json +0 -6
- package/app/routes/mobile-prevented/mobilePrevented.module.css +0 -47
- package/app/routes/mobile-prevented/mobilePrevented.tsx +0 -26
- package/app/routes/mobile-prevented/route.ts +0 -14
- package/app/utils/device-detection.ts +0 -5
- package/app/utils/html-sanitizer.ts +0 -80
- package/app/utils/meta.ts +0 -48
- package/public/icon-256.png +0 -0
- package/public/icon-512.png +0 -0
- package/public/manifest.json +0 -25
- package/public/shortcut.png +0 -0
- package/public/social-image.png +0 -0
|
@@ -111,7 +111,7 @@ export const BoxAnnotations = ({
|
|
|
111
111
|
x: Math.max(0, Math.min(100, x)),
|
|
112
112
|
y: Math.max(0, Math.min(100, y))
|
|
113
113
|
};
|
|
114
|
-
} catch
|
|
114
|
+
} catch {
|
|
115
115
|
return { x: 0, y: 0 };
|
|
116
116
|
}
|
|
117
117
|
}, [imageRef]);
|
|
@@ -143,7 +143,7 @@ export const BoxAnnotations = ({
|
|
|
143
143
|
x: Math.max(DIALOG_OFFSET, adjustedX),
|
|
144
144
|
y: Math.max(DIALOG_OFFSET, adjustedY)
|
|
145
145
|
};
|
|
146
|
-
}, []);
|
|
146
|
+
}, [imageRef]);
|
|
147
147
|
|
|
148
148
|
// Handle mouse down - start drawing
|
|
149
149
|
const handleMouseDown = useCallback((e: React.MouseEvent) => {
|
|
@@ -173,7 +173,7 @@ export const BoxAnnotations = ({
|
|
|
173
173
|
currentY: y
|
|
174
174
|
});
|
|
175
175
|
}
|
|
176
|
-
}, [isAnnotationMode, getRelativeCoordinates]);
|
|
176
|
+
}, [isReadOnly, isAnnotationMode, imageRef, getRelativeCoordinates]);
|
|
177
177
|
|
|
178
178
|
// Handle mouse move - update current drawing box
|
|
179
179
|
const handleMouseMove = useCallback((e: React.MouseEvent) => {
|
|
@@ -281,9 +281,14 @@ export const BoxAnnotations = ({
|
|
|
281
281
|
annotationColor,
|
|
282
282
|
annotations,
|
|
283
283
|
onAnnotationsChange,
|
|
284
|
+
annotationData,
|
|
285
|
+
onAnnotationDataChange,
|
|
284
286
|
generateAnnotationId,
|
|
285
287
|
calculateDialogPosition,
|
|
286
|
-
user
|
|
288
|
+
user,
|
|
289
|
+
caseNumber,
|
|
290
|
+
imageFileId,
|
|
291
|
+
originalImageFileName
|
|
287
292
|
]);
|
|
288
293
|
|
|
289
294
|
// Remove a box annotation with validation
|
|
@@ -364,7 +369,16 @@ export const BoxAnnotations = ({
|
|
|
364
369
|
console.error('Failed to remove annotation or log audit:', error);
|
|
365
370
|
// Continue with removal even if audit logging fails
|
|
366
371
|
}
|
|
367
|
-
}, [
|
|
372
|
+
}, [
|
|
373
|
+
annotations,
|
|
374
|
+
onAnnotationsChange,
|
|
375
|
+
annotationData,
|
|
376
|
+
onAnnotationDataChange,
|
|
377
|
+
user,
|
|
378
|
+
caseNumber,
|
|
379
|
+
imageFileId,
|
|
380
|
+
originalImageFileName
|
|
381
|
+
]);
|
|
368
382
|
|
|
369
383
|
// Handle right-click to remove annotation
|
|
370
384
|
const handleAnnotationRightClick = useCallback((e: React.MouseEvent, annotationId: string) => {
|
|
@@ -461,7 +475,17 @@ export const BoxAnnotations = ({
|
|
|
461
475
|
// Still try to close dialog even if update fails
|
|
462
476
|
setLabelDialog({ isVisible: false, annotationId: null, x: 0, y: 0, label: '' });
|
|
463
477
|
}
|
|
464
|
-
}, [
|
|
478
|
+
}, [
|
|
479
|
+
labelDialog,
|
|
480
|
+
annotations,
|
|
481
|
+
onAnnotationsChange,
|
|
482
|
+
annotationData,
|
|
483
|
+
onAnnotationDataChange,
|
|
484
|
+
user,
|
|
485
|
+
caseNumber,
|
|
486
|
+
imageFileId,
|
|
487
|
+
originalImageFileName
|
|
488
|
+
]);
|
|
465
489
|
|
|
466
490
|
// Handle label cancellation
|
|
467
491
|
const handleLabelCancel = useCallback(() => {
|
|
@@ -584,7 +608,6 @@ export const BoxAnnotations = ({
|
|
|
584
608
|
onKeyDown={handleLabelKeyDown}
|
|
585
609
|
placeholder="Enter label..."
|
|
586
610
|
className={styles.labelInput}
|
|
587
|
-
autoFocus
|
|
588
611
|
/>
|
|
589
612
|
<div className={styles.labelDialogButtons}>
|
|
590
613
|
<button
|
|
@@ -620,6 +643,12 @@ export const BoxAnnotations = ({
|
|
|
620
643
|
onMouseMove={handleMouseMove}
|
|
621
644
|
onMouseUp={handleMouseUp}
|
|
622
645
|
onMouseLeave={handleMouseUp}
|
|
646
|
+
onKeyDown={() => {
|
|
647
|
+
// Keyboard interactions are handled by parent canvas tools.
|
|
648
|
+
}}
|
|
649
|
+
role="button"
|
|
650
|
+
tabIndex={0}
|
|
651
|
+
aria-label="Box annotation canvas"
|
|
623
652
|
style={{
|
|
624
653
|
cursor: isAnnotationMode && !isReadOnly ? 'crosshair' : 'default',
|
|
625
654
|
pointerEvents: 'auto' // Always allow pointer events for viewing annotations
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { useEffect, useState, useRef, useContext } from 'react';
|
|
1
|
+
import { useEffect, useState, useRef, useContext, useCallback } from 'react';
|
|
2
2
|
import { BoxAnnotations } from './box-annotations/box-annotations';
|
|
3
3
|
import { ConfirmationModal } from './confirmation/confirmation';
|
|
4
4
|
import { AnnotationData, BoxAnnotation, ConfirmationData } from '~/types/annotations';
|
|
5
5
|
import { AuthContext } from '~/contexts/auth.context';
|
|
6
6
|
import { storeConfirmation } from '~/components/actions/confirm-export';
|
|
7
|
-
import { auditService } from '~/services/audit.service';
|
|
8
7
|
import styles from './canvas.module.css';
|
|
9
8
|
|
|
10
9
|
interface CanvasProps {
|
|
@@ -51,6 +50,15 @@ export const Canvas = ({
|
|
|
51
50
|
const [isConfirmationModalOpen, setIsConfirmationModalOpen] = useState(false);
|
|
52
51
|
const imageRef = useRef<HTMLImageElement>(null);
|
|
53
52
|
|
|
53
|
+
const resetImageLoadState = useCallback(() => {
|
|
54
|
+
setLoadError(undefined);
|
|
55
|
+
setIsLoading(false);
|
|
56
|
+
}, []);
|
|
57
|
+
|
|
58
|
+
const clearFlashingState = useCallback(() => {
|
|
59
|
+
setIsFlashing(false);
|
|
60
|
+
}, []);
|
|
61
|
+
|
|
54
62
|
// Handle box annotation changes
|
|
55
63
|
const handleBoxAnnotationsChange = (boxAnnotations: BoxAnnotation[]) => {
|
|
56
64
|
if (!onAnnotationUpdate || !annotationData || isReadOnly || annotationData.confirmationData) return;
|
|
@@ -114,13 +122,19 @@ export const Canvas = ({
|
|
|
114
122
|
|
|
115
123
|
useEffect(() => {
|
|
116
124
|
if (!imageUrl) {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
125
|
+
const resetTimer = window.setTimeout(() => {
|
|
126
|
+
resetImageLoadState();
|
|
127
|
+
}, 0);
|
|
128
|
+
|
|
129
|
+
return () => {
|
|
130
|
+
window.clearTimeout(resetTimer);
|
|
131
|
+
};
|
|
120
132
|
}
|
|
121
133
|
|
|
122
|
-
|
|
123
|
-
|
|
134
|
+
const startLoadingTimer = window.setTimeout(() => {
|
|
135
|
+
setIsLoading(true);
|
|
136
|
+
setLoadError(undefined);
|
|
137
|
+
}, 0);
|
|
124
138
|
|
|
125
139
|
const img = new Image();
|
|
126
140
|
|
|
@@ -129,36 +143,33 @@ export const Canvas = ({
|
|
|
129
143
|
setLoadError(undefined);
|
|
130
144
|
};
|
|
131
145
|
|
|
132
|
-
img.onerror = (
|
|
146
|
+
img.onerror = () => {
|
|
133
147
|
setLoadError({
|
|
134
148
|
type: 'load',
|
|
135
|
-
message:
|
|
149
|
+
message: 'Failed to load image: Unknown error'
|
|
136
150
|
});
|
|
137
151
|
setIsLoading(false);
|
|
138
152
|
};
|
|
139
153
|
|
|
140
|
-
|
|
141
|
-
img.src = imageUrl;
|
|
142
|
-
} catch (e) {
|
|
143
|
-
setLoadError({
|
|
144
|
-
type: 'invalid',
|
|
145
|
-
message: 'Invalid image URL provided'
|
|
146
|
-
});
|
|
147
|
-
setIsLoading(false);
|
|
148
|
-
}
|
|
154
|
+
img.src = imageUrl;
|
|
149
155
|
|
|
150
156
|
return () => {
|
|
157
|
+
window.clearTimeout(startLoadingTimer);
|
|
151
158
|
img.onload = null;
|
|
152
159
|
img.onerror = null;
|
|
153
|
-
|
|
154
|
-
setIsLoading(false);
|
|
160
|
+
resetImageLoadState();
|
|
155
161
|
};
|
|
156
|
-
}, [imageUrl]);
|
|
162
|
+
}, [imageUrl, resetImageLoadState]);
|
|
157
163
|
|
|
158
164
|
useEffect(() => {
|
|
159
165
|
if (!activeAnnotations?.has('class') || !annotationData?.hasSubclass) {
|
|
160
|
-
|
|
161
|
-
|
|
166
|
+
const flashResetTimer = window.setTimeout(() => {
|
|
167
|
+
clearFlashingState();
|
|
168
|
+
}, 0);
|
|
169
|
+
|
|
170
|
+
return () => {
|
|
171
|
+
window.clearTimeout(flashResetTimer);
|
|
172
|
+
};
|
|
162
173
|
}
|
|
163
174
|
|
|
164
175
|
const flashInterval = setInterval(() => {
|
|
@@ -171,7 +182,7 @@ export const Canvas = ({
|
|
|
171
182
|
}, 60000);
|
|
172
183
|
|
|
173
184
|
return () => clearInterval(flashInterval);
|
|
174
|
-
}, [activeAnnotations, annotationData?.hasSubclass]);
|
|
185
|
+
}, [activeAnnotations, annotationData?.hasSubclass, clearFlashingState]);
|
|
175
186
|
|
|
176
187
|
const getErrorMessage = () => {
|
|
177
188
|
if (error) return error;
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
justify-content: center;
|
|
7
7
|
align-items: center;
|
|
8
8
|
z-index: var(--zIndex5);
|
|
9
|
+
cursor: default;
|
|
9
10
|
transition: background-color var(--durationM) var(--bezierFastoutSlowin);
|
|
10
11
|
}
|
|
11
12
|
|
|
@@ -15,7 +16,9 @@
|
|
|
15
16
|
width: 90%;
|
|
16
17
|
max-width: 400px;
|
|
17
18
|
max-height: 90vh;
|
|
18
|
-
box-shadow: 0 var(--spaceXS) var(--spaceL)
|
|
19
|
+
box-shadow: 0 var(--spaceXS) var(--spaceL)
|
|
20
|
+
color-mix(in lab, var(--black) 10%, transparent);
|
|
21
|
+
cursor: default;
|
|
19
22
|
transition: background-color var(--durationM) var(--bezierFastoutSlowin);
|
|
20
23
|
}
|
|
21
24
|
|
|
@@ -106,7 +109,7 @@
|
|
|
106
109
|
border-radius: var(--spaceXS);
|
|
107
110
|
font-size: var(--fontSizeBodyXS);
|
|
108
111
|
color: var(--text);
|
|
109
|
-
font-family:
|
|
112
|
+
font-family: "Inter", monospace;
|
|
110
113
|
}
|
|
111
114
|
|
|
112
115
|
.error {
|
|
@@ -104,14 +104,32 @@ export const ConfirmationModal = ({ isOpen, onClose, onConfirm, company, existin
|
|
|
104
104
|
}
|
|
105
105
|
};
|
|
106
106
|
|
|
107
|
-
const
|
|
107
|
+
const handleOverlayMouseDown = (e: React.MouseEvent<HTMLDivElement>) => {
|
|
108
108
|
if (e.target === e.currentTarget) {
|
|
109
109
|
onClose();
|
|
110
110
|
}
|
|
111
111
|
};
|
|
112
112
|
|
|
113
|
+
const handleOverlayKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {
|
|
114
|
+
if (e.target !== e.currentTarget) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
119
|
+
e.preventDefault();
|
|
120
|
+
onClose();
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
|
|
113
124
|
return (
|
|
114
|
-
<div
|
|
125
|
+
<div
|
|
126
|
+
className={styles.overlay}
|
|
127
|
+
onMouseDown={handleOverlayMouseDown}
|
|
128
|
+
onKeyDown={handleOverlayKeyDown}
|
|
129
|
+
role="button"
|
|
130
|
+
tabIndex={0}
|
|
131
|
+
aria-label="Close confirmation dialog"
|
|
132
|
+
>
|
|
115
133
|
<div className={styles.modal}>
|
|
116
134
|
<div className={styles.header}>
|
|
117
135
|
<h2 className={styles.title}>
|
|
@@ -135,7 +153,7 @@ export const ConfirmationModal = ({ isOpen, onClose, onConfirm, company, existin
|
|
|
135
153
|
<div className={styles.content}>
|
|
136
154
|
<div className={styles.fieldGroup}>
|
|
137
155
|
<div className={styles.field}>
|
|
138
|
-
<
|
|
156
|
+
<span className={styles.label}>Name:</span>
|
|
139
157
|
<div className={styles.readOnlyValue}>
|
|
140
158
|
{hasExistingConfirmation ? existingConfirmation.fullName : fullName}
|
|
141
159
|
</div>
|
|
@@ -154,33 +172,32 @@ export const ConfirmationModal = ({ isOpen, onClose, onConfirm, company, existin
|
|
|
154
172
|
}}
|
|
155
173
|
placeholder="Enter your badge or ID number"
|
|
156
174
|
disabled={isConfirming || hasExistingConfirmation}
|
|
157
|
-
autoFocus={!hasExistingConfirmation}
|
|
158
175
|
/>
|
|
159
176
|
</div>
|
|
160
177
|
|
|
161
178
|
<div className={styles.field}>
|
|
162
|
-
<
|
|
179
|
+
<span className={styles.label}>Email:</span>
|
|
163
180
|
<div className={styles.readOnlyValue}>
|
|
164
181
|
{hasExistingConfirmation ? existingConfirmation.confirmedByEmail : userEmail}
|
|
165
182
|
</div>
|
|
166
183
|
</div>
|
|
167
184
|
|
|
168
185
|
<div className={styles.field}>
|
|
169
|
-
<
|
|
186
|
+
<span className={styles.label}>Lab/Company:</span>
|
|
170
187
|
<div className={styles.readOnlyValue}>
|
|
171
188
|
{hasExistingConfirmation ? existingConfirmation.confirmedByCompany : labCompany}
|
|
172
189
|
</div>
|
|
173
190
|
</div>
|
|
174
191
|
|
|
175
192
|
<div className={styles.field}>
|
|
176
|
-
<
|
|
193
|
+
<span className={styles.label}>Timestamp:</span>
|
|
177
194
|
<div className={styles.readOnlyValue}>
|
|
178
195
|
{hasExistingConfirmation ? existingConfirmation.timestamp : timestamp}
|
|
179
196
|
</div>
|
|
180
197
|
</div>
|
|
181
198
|
|
|
182
199
|
<div className={styles.field}>
|
|
183
|
-
<
|
|
200
|
+
<span className={styles.label}>Confirmation ID:</span>
|
|
184
201
|
<div className={styles.readOnlyValue}>
|
|
185
202
|
{hasExistingConfirmation ? existingConfirmation.confirmationId : confirmationId}
|
|
186
203
|
</div>
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
justify-content: center;
|
|
7
7
|
align-items: center;
|
|
8
8
|
z-index: var(--zIndex5);
|
|
9
|
+
cursor: default;
|
|
9
10
|
transition: background-color var(--durationM) var(--bezierFastoutSlowin);
|
|
10
11
|
}
|
|
11
12
|
|
|
@@ -15,7 +16,12 @@
|
|
|
15
16
|
width: 90%;
|
|
16
17
|
max-width: 480px;
|
|
17
18
|
max-height: 90vh;
|
|
18
|
-
|
|
19
|
+
display: flex;
|
|
20
|
+
flex-direction: column;
|
|
21
|
+
overflow: hidden;
|
|
22
|
+
box-shadow: 0 var(--spaceXS) var(--spaceL)
|
|
23
|
+
color-mix(in lab, var(--black) 10%, transparent);
|
|
24
|
+
cursor: default;
|
|
19
25
|
transition: background-color var(--durationM) var(--bezierFastoutSlowin);
|
|
20
26
|
}
|
|
21
27
|
|
|
@@ -52,8 +58,10 @@
|
|
|
52
58
|
|
|
53
59
|
.content {
|
|
54
60
|
padding: var(--spaceL);
|
|
61
|
+
flex: 1 1 auto;
|
|
62
|
+
min-height: 0;
|
|
55
63
|
overflow-y: auto;
|
|
56
|
-
|
|
64
|
+
overflow-x: hidden;
|
|
57
65
|
}
|
|
58
66
|
|
|
59
67
|
.formatSelector {
|
|
@@ -154,7 +162,7 @@
|
|
|
154
162
|
}
|
|
155
163
|
|
|
156
164
|
.checkbox:checked::after {
|
|
157
|
-
content:
|
|
165
|
+
content: "";
|
|
158
166
|
position: absolute;
|
|
159
167
|
left: 3px;
|
|
160
168
|
top: 0px;
|
|
@@ -191,6 +199,7 @@
|
|
|
191
199
|
}
|
|
192
200
|
|
|
193
201
|
.checkboxTooltip {
|
|
202
|
+
display: block;
|
|
194
203
|
font-size: var(--fontSizeBodyXS);
|
|
195
204
|
color: var(--textBody);
|
|
196
205
|
margin: 0;
|
|
@@ -286,6 +295,186 @@
|
|
|
286
295
|
box-shadow: none;
|
|
287
296
|
}
|
|
288
297
|
|
|
298
|
+
.publicKeySection {
|
|
299
|
+
margin-top: var(--spaceS);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
.publicKeyButton {
|
|
303
|
+
width: 100%;
|
|
304
|
+
background: transparent;
|
|
305
|
+
color: var(--primary);
|
|
306
|
+
border: 1px solid color-mix(in lab, var(--primary) 35%, transparent);
|
|
307
|
+
border-radius: var(--spaceXS);
|
|
308
|
+
padding: var(--spaceS) var(--spaceM);
|
|
309
|
+
font-size: var(--fontSizeBodyS);
|
|
310
|
+
font-weight: var(--fontWeightMedium);
|
|
311
|
+
cursor: pointer;
|
|
312
|
+
transition: all var(--durationS) var(--bezierFastoutSlowin);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
.publicKeyButton:hover {
|
|
316
|
+
background: color-mix(in lab, var(--primary) 10%, transparent);
|
|
317
|
+
border-color: color-mix(in lab, var(--primary) 55%, transparent);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
.publicKeyOverlay {
|
|
321
|
+
position: fixed;
|
|
322
|
+
inset: 0;
|
|
323
|
+
background-color: color-mix(in lab, var(--background) 60%, transparent);
|
|
324
|
+
display: flex;
|
|
325
|
+
justify-content: center;
|
|
326
|
+
align-items: center;
|
|
327
|
+
z-index: var(--zIndex5);
|
|
328
|
+
padding: var(--spaceL);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
.publicKeyModal {
|
|
332
|
+
width: 100%;
|
|
333
|
+
max-width: 640px;
|
|
334
|
+
max-height: 90vw;
|
|
335
|
+
background: var(--backgroundLight);
|
|
336
|
+
border-radius: var(--spaceXS);
|
|
337
|
+
display: flex;
|
|
338
|
+
flex-direction: column;
|
|
339
|
+
box-shadow: 0 var(--spaceXS) var(--spaceL)
|
|
340
|
+
color-mix(in lab, var(--black) 18%, transparent);
|
|
341
|
+
overflow: hidden;
|
|
342
|
+
cursor: default;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
.publicKeyHeader {
|
|
346
|
+
display: flex;
|
|
347
|
+
justify-content: space-between;
|
|
348
|
+
align-items: center;
|
|
349
|
+
padding: var(--spaceL);
|
|
350
|
+
border-bottom: 1px solid color-mix(in lab, var(--text) 10%, transparent);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
.publicKeyTitle {
|
|
354
|
+
margin: 0;
|
|
355
|
+
font-size: var(--fontSizeBodyL);
|
|
356
|
+
font-weight: 600;
|
|
357
|
+
color: var(--textTitle);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
.publicKeyContent {
|
|
361
|
+
padding: var(--spaceL);
|
|
362
|
+
flex: 1 1 auto;
|
|
363
|
+
min-height: 0;
|
|
364
|
+
display: flex;
|
|
365
|
+
flex-direction: column;
|
|
366
|
+
gap: var(--spaceM);
|
|
367
|
+
overflow-y: auto;
|
|
368
|
+
overflow-x: hidden;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
.publicKeyDescription {
|
|
372
|
+
margin: 0;
|
|
373
|
+
font-size: var(--fontSizeBodyS);
|
|
374
|
+
color: var(--textBody);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
.publicKeyMeta {
|
|
378
|
+
margin: 0;
|
|
379
|
+
font-size: var(--fontSizeBodyS);
|
|
380
|
+
color: var(--textTitle);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
.publicKeyMeta span {
|
|
384
|
+
font-weight: var(--fontWeightMedium);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
.publicKeyLabel {
|
|
388
|
+
font-size: var(--fontSizeBodyXS);
|
|
389
|
+
font-weight: var(--fontWeightMedium);
|
|
390
|
+
color: var(--textTitle);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
.publicKeyField {
|
|
394
|
+
width: 100%;
|
|
395
|
+
max-width: 100%;
|
|
396
|
+
box-sizing: border-box;
|
|
397
|
+
min-height: 180px;
|
|
398
|
+
padding: var(--spaceM);
|
|
399
|
+
border: 1px solid color-mix(in lab, var(--text) 10%, transparent);
|
|
400
|
+
border-radius: var(--spaceXS);
|
|
401
|
+
background: color-mix(in lab, var(--background) 96%, transparent);
|
|
402
|
+
color: var(--textBody);
|
|
403
|
+
font-size: var(--fontSizeBodyXS);
|
|
404
|
+
line-height: 1.4;
|
|
405
|
+
font-family: Consolas, "Courier New", monospace;
|
|
406
|
+
resize: vertical;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
.publicKeyHowToTitle {
|
|
410
|
+
margin: 0;
|
|
411
|
+
font-size: var(--fontSizeBodyS);
|
|
412
|
+
font-weight: var(--fontWeightMedium);
|
|
413
|
+
color: var(--textTitle);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
.publicKeyHowToList {
|
|
417
|
+
margin: 0;
|
|
418
|
+
padding-left: var(--spaceL);
|
|
419
|
+
display: flex;
|
|
420
|
+
flex-direction: column;
|
|
421
|
+
gap: var(--spaceXS);
|
|
422
|
+
color: var(--textBody);
|
|
423
|
+
font-size: var(--fontSizeBodyS);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
.publicKeyActions {
|
|
427
|
+
display: flex;
|
|
428
|
+
justify-content: flex-end;
|
|
429
|
+
gap: var(--spaceS);
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
.publicKeyStatus {
|
|
433
|
+
margin: 0;
|
|
434
|
+
font-size: var(--fontSizeBodyXS);
|
|
435
|
+
color: var(--textBody);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
.publicKeyCopyButton {
|
|
439
|
+
background: transparent;
|
|
440
|
+
color: var(--primary);
|
|
441
|
+
border: 1px solid color-mix(in lab, var(--primary) 35%, transparent);
|
|
442
|
+
border-radius: var(--spaceXS);
|
|
443
|
+
padding: var(--spaceS) var(--spaceL);
|
|
444
|
+
font-size: var(--fontSizeBodyS);
|
|
445
|
+
font-weight: var(--fontWeightMedium);
|
|
446
|
+
cursor: pointer;
|
|
447
|
+
transition: all var(--durationS) var(--bezierFastoutSlowin);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
.publicKeyCopyButton:hover:not(:disabled) {
|
|
451
|
+
background: color-mix(in lab, var(--primary) 10%, transparent);
|
|
452
|
+
border-color: color-mix(in lab, var(--primary) 55%, transparent);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
.publicKeyCopyButton:disabled {
|
|
456
|
+
background: color-mix(in lab, var(--background) 95%, transparent);
|
|
457
|
+
color: var(--textLight);
|
|
458
|
+
border-color: color-mix(in lab, var(--text) 10%, transparent);
|
|
459
|
+
cursor: not-allowed;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
.publicKeyCloseButton {
|
|
463
|
+
background: var(--primary);
|
|
464
|
+
color: white;
|
|
465
|
+
border: none;
|
|
466
|
+
border-radius: var(--spaceXS);
|
|
467
|
+
padding: var(--spaceS) var(--spaceL);
|
|
468
|
+
font-size: var(--fontSizeBodyS);
|
|
469
|
+
font-weight: var(--fontWeightMedium);
|
|
470
|
+
cursor: pointer;
|
|
471
|
+
transition: all var(--durationS) var(--bezierFastoutSlowin);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
.publicKeyCloseButton:hover {
|
|
475
|
+
background: color-mix(in lab, var(--primary) 85%, var(--black));
|
|
476
|
+
}
|
|
477
|
+
|
|
289
478
|
.divider {
|
|
290
479
|
margin: var(--spaceL) 0;
|
|
291
480
|
text-align: center;
|
|
@@ -296,7 +485,7 @@
|
|
|
296
485
|
}
|
|
297
486
|
|
|
298
487
|
.divider::before {
|
|
299
|
-
content:
|
|
488
|
+
content: "";
|
|
300
489
|
position: absolute;
|
|
301
490
|
top: 50%;
|
|
302
491
|
left: 0;
|
|
@@ -383,4 +572,4 @@
|
|
|
383
572
|
color: var(--error);
|
|
384
573
|
font-size: var(--fontSizeBodyS);
|
|
385
574
|
font-weight: var(--fontWeightMedium);
|
|
386
|
-
}
|
|
575
|
+
}
|