This commit is contained in:
parent
ef5f977f8a
commit
d7871736c8
10 changed files with 566 additions and 8 deletions
|
|
@ -13,6 +13,12 @@ export function ScreenshotsModule({ toolboxId, moduleId, context, editing }) {
|
|||
}
|
||||
}
|
||||
|
||||
function updateShot(shotId, patch) {
|
||||
context.setModuleData(toolboxId, moduleId, {
|
||||
shots: data.shots.map((shot) => shot.id === shotId ? { ...shot, ...patch } : shot)
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{editing && (
|
||||
|
|
@ -66,6 +72,17 @@ export function ScreenshotsModule({ toolboxId, moduleId, context, editing }) {
|
|||
<button className="shot-preview" onClick={() => context.setScreenshot(shot)} aria-label={textContent.previewAriaLabel || "Agrandir l'image"}>
|
||||
<img src={shot.dataUrl} alt={textContent.imageAlt || "Image"} />
|
||||
</button>
|
||||
{editing ? (
|
||||
<input
|
||||
className="shot-label-input"
|
||||
value={shot.label || ""}
|
||||
placeholder={textContent.labelPlaceholder || "Libellé de l'image"}
|
||||
onChange={(event) => updateShot(shot.id, { label: event.target.value })}
|
||||
aria-label={textContent.labelAriaLabel || "Libellé de l'image"}
|
||||
/>
|
||||
) : shot.label ? (
|
||||
<figcaption className="shot-label">{shot.label}</figcaption>
|
||||
) : null}
|
||||
<div className="shot-actions">
|
||||
<button
|
||||
className="shot-annotate-button"
|
||||
|
|
|
|||
|
|
@ -241,6 +241,11 @@ function normalizeCalculatorValue(value) {
|
|||
return Number.isFinite(parsed) ? parsed : 0;
|
||||
}
|
||||
|
||||
function labelFromFileName(name) {
|
||||
if (!name || name === "image.png") return "";
|
||||
return name.replace(/\.[^.]+$/, "").trim();
|
||||
}
|
||||
|
||||
function normalizeCalculatorData(data) {
|
||||
const entries = (data?.entries || [])
|
||||
.map((entry) => ({
|
||||
|
|
@ -313,7 +318,11 @@ function compactModuleDataForStorage(type, value) {
|
|||
if (type === "screenshots") {
|
||||
const shots = (Array.isArray(value?.shots) ? value.shots : [])
|
||||
.filter((shot) => shot?.dataUrl)
|
||||
.map((shot) => ({ id: shot.id || uid("shot"), dataUrl: shot.dataUrl }));
|
||||
.map((shot) => {
|
||||
const compact = { id: shot.id || uid("shot"), dataUrl: shot.dataUrl };
|
||||
if (shot.label) compact.label = shot.label;
|
||||
return compact;
|
||||
});
|
||||
return shots.length ? { shots } : null;
|
||||
}
|
||||
if (type === "imageAnnotation") {
|
||||
|
|
@ -798,7 +807,10 @@ function App() {
|
|||
if (!imageFiles.length) return false;
|
||||
const data = store.getModuleData(toolboxId, moduleId, { shots: [] });
|
||||
for (const file of imageFiles) {
|
||||
data.shots.unshift({ id: uid("shot"), dataUrl: await compressImage(file) });
|
||||
const shot = { id: uid("shot"), dataUrl: await compressImage(file) };
|
||||
const label = labelFromFileName(file.name);
|
||||
if (label) shot.label = label;
|
||||
data.shots.unshift(shot);
|
||||
}
|
||||
return store.updateModuleData(toolboxId, moduleId, data);
|
||||
}
|
||||
|
|
@ -1812,10 +1824,13 @@ function ScreenshotViewer({ shot, onClose }) {
|
|||
<div className="screenshot-viewer-backdrop" onClick={onClose} />
|
||||
<section ref={viewerRef} className="screenshot-viewer" role="dialog" aria-modal="true" aria-label="Screenshot">
|
||||
<header>
|
||||
{!canAnnotate && !hasMarkers && (
|
||||
<button className="screenshot-viewer-button" onClick={() => openImageInNewTab(shot.dataUrl)} aria-label="Ouvrir l'image en taille réelle" title="Taille réelle"><Icon name="zoom" /></button>
|
||||
)}
|
||||
<button className="screenshot-viewer-button" onClick={onClose} aria-label="Fermer" title="Fermer"><Icon name="close" /></button>
|
||||
{shot.label && <strong className="screenshot-viewer-title">{shot.label}</strong>}
|
||||
<div className="screenshot-viewer-actions">
|
||||
{!canAnnotate && !hasMarkers && (
|
||||
<button className="screenshot-viewer-button" onClick={() => openImageInNewTab(shot.dataUrl)} aria-label="Ouvrir l'image en taille réelle" title="Taille réelle"><Icon name="zoom" /></button>
|
||||
)}
|
||||
<button className="screenshot-viewer-button" onClick={onClose} aria-label="Fermer" title="Fermer"><Icon name="close" /></button>
|
||||
</div>
|
||||
</header>
|
||||
<div className={`screenshot-viewer-body ${canAnnotate ? "has-annotation-side" : ""}`}>
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -31,8 +31,22 @@
|
|||
}
|
||||
|
||||
.screenshot-viewer header {
|
||||
display: flex;
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) auto;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
}
|
||||
|
||||
.screenshot-viewer-title {
|
||||
overflow: hidden;
|
||||
color: var(--color-text);
|
||||
font-size: var(--font-size-md);
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.screenshot-viewer-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: var(--space-2);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1710,6 +1710,8 @@ textarea:focus {
|
|||
|
||||
.shots figure {
|
||||
position: relative;
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
margin: 0;
|
||||
padding: 8px;
|
||||
border: 1px solid var(--color-border);
|
||||
|
|
@ -1732,6 +1734,40 @@ textarea:focus {
|
|||
box-shadow: 0 0 0 2px rgba(246, 196, 83, 0.28);
|
||||
}
|
||||
|
||||
.shot-label,
|
||||
.shot-label-input {
|
||||
min-width: 0;
|
||||
font-size: var(--font-size-sm);
|
||||
}
|
||||
|
||||
.shot-label {
|
||||
overflow: hidden;
|
||||
color: var(--color-text-secondary);
|
||||
font-weight: 700;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.shot-label-input {
|
||||
width: 100%;
|
||||
min-height: 36px;
|
||||
padding: 0 10px;
|
||||
border: 1px solid rgba(138, 150, 197, 0.2);
|
||||
border-radius: var(--radius-md);
|
||||
background: rgba(8, 13, 30, 0.62);
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.shot-label-input::placeholder {
|
||||
color: rgba(185, 194, 215, 0.48);
|
||||
}
|
||||
|
||||
.shot-label-input:focus {
|
||||
border-color: rgba(246, 196, 83, 0.72);
|
||||
outline: none;
|
||||
box-shadow: 0 0 0 3px rgba(246, 196, 83, 0.14);
|
||||
}
|
||||
|
||||
.shots img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
|
|
@ -1744,7 +1780,6 @@ textarea:focus {
|
|||
.shot-actions {
|
||||
display: flex;
|
||||
gap: var(--space-2);
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.shot-actions .shot-annotate-button,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue