@jhits/plugin-images 0.0.8 → 0.0.10

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.
Files changed (102) hide show
  1. package/package.json +15 -9
  2. package/src/api/fallback/route.ts +0 -69
  3. package/src/api/index.ts +0 -10
  4. package/src/api/list/index.ts +0 -96
  5. package/src/api/resolve/route.ts +0 -241
  6. package/src/api/router.ts +0 -85
  7. package/src/api/upload/index.ts +0 -88
  8. package/src/api/uploads/[filename]/route.ts +0 -93
  9. package/src/api-server.ts +0 -11
  10. package/src/assets/noimagefound.jpg +0 -0
  11. package/src/components/BackgroundImage.d.ts +0 -11
  12. package/src/components/BackgroundImage.d.ts.map +0 -1
  13. package/src/components/BackgroundImage.js +0 -35
  14. package/src/components/BackgroundImage.tsx +0 -92
  15. package/src/components/GlobalImageEditor/config.d.ts +0 -9
  16. package/src/components/GlobalImageEditor/config.d.ts.map +0 -1
  17. package/src/components/GlobalImageEditor/config.js +0 -18
  18. package/src/components/GlobalImageEditor/config.ts +0 -21
  19. package/src/components/GlobalImageEditor/eventHandlers.d.ts +0 -20
  20. package/src/components/GlobalImageEditor/eventHandlers.d.ts.map +0 -1
  21. package/src/components/GlobalImageEditor/eventHandlers.js +0 -206
  22. package/src/components/GlobalImageEditor/eventHandlers.ts +0 -267
  23. package/src/components/GlobalImageEditor/imageDetection.d.ts +0 -16
  24. package/src/components/GlobalImageEditor/imageDetection.d.ts.map +0 -1
  25. package/src/components/GlobalImageEditor/imageDetection.js +0 -130
  26. package/src/components/GlobalImageEditor/imageDetection.ts +0 -160
  27. package/src/components/GlobalImageEditor/imageSetup.d.ts +0 -9
  28. package/src/components/GlobalImageEditor/imageSetup.d.ts.map +0 -1
  29. package/src/components/GlobalImageEditor/imageSetup.js +0 -261
  30. package/src/components/GlobalImageEditor/imageSetup.ts +0 -306
  31. package/src/components/GlobalImageEditor/saveLogic.d.ts +0 -26
  32. package/src/components/GlobalImageEditor/saveLogic.d.ts.map +0 -1
  33. package/src/components/GlobalImageEditor/saveLogic.js +0 -99
  34. package/src/components/GlobalImageEditor/saveLogic.ts +0 -133
  35. package/src/components/GlobalImageEditor/stylingDetection.d.ts +0 -9
  36. package/src/components/GlobalImageEditor/stylingDetection.d.ts.map +0 -1
  37. package/src/components/GlobalImageEditor/stylingDetection.js +0 -110
  38. package/src/components/GlobalImageEditor/stylingDetection.ts +0 -122
  39. package/src/components/GlobalImageEditor/transformParsing.d.ts +0 -16
  40. package/src/components/GlobalImageEditor/transformParsing.d.ts.map +0 -1
  41. package/src/components/GlobalImageEditor/transformParsing.js +0 -68
  42. package/src/components/GlobalImageEditor/transformParsing.ts +0 -83
  43. package/src/components/GlobalImageEditor/types.d.ts +0 -36
  44. package/src/components/GlobalImageEditor/types.d.ts.map +0 -1
  45. package/src/components/GlobalImageEditor/types.js +0 -4
  46. package/src/components/GlobalImageEditor/types.ts +0 -39
  47. package/src/components/GlobalImageEditor.d.ts +0 -8
  48. package/src/components/GlobalImageEditor.d.ts.map +0 -1
  49. package/src/components/GlobalImageEditor.js +0 -227
  50. package/src/components/GlobalImageEditor.tsx +0 -327
  51. package/src/components/Image.d.ts +0 -22
  52. package/src/components/Image.d.ts.map +0 -1
  53. package/src/components/Image.js +0 -229
  54. package/src/components/Image.tsx +0 -343
  55. package/src/components/ImageBrowserModal.d.ts +0 -13
  56. package/src/components/ImageBrowserModal.d.ts.map +0 -1
  57. package/src/components/ImageBrowserModal.js +0 -504
  58. package/src/components/ImageBrowserModal.tsx +0 -837
  59. package/src/components/ImageEditor.d.ts +0 -27
  60. package/src/components/ImageEditor.d.ts.map +0 -1
  61. package/src/components/ImageEditor.js +0 -173
  62. package/src/components/ImageEditor.tsx +0 -323
  63. package/src/components/ImageEffectsPanel.tsx +0 -116
  64. package/src/components/ImagePicker.d.ts +0 -3
  65. package/src/components/ImagePicker.d.ts.map +0 -1
  66. package/src/components/ImagePicker.js +0 -143
  67. package/src/components/ImagePicker.tsx +0 -265
  68. package/src/components/ImagesPluginInit.d.ts +0 -24
  69. package/src/components/ImagesPluginInit.d.ts.map +0 -1
  70. package/src/components/ImagesPluginInit.js +0 -28
  71. package/src/components/ImagesPluginInit.tsx +0 -31
  72. package/src/components/index.ts +0 -10
  73. package/src/config.ts +0 -179
  74. package/src/hooks/useImagePicker.d.ts +0 -20
  75. package/src/hooks/useImagePicker.d.ts.map +0 -1
  76. package/src/hooks/useImagePicker.js +0 -322
  77. package/src/hooks/useImagePicker.ts +0 -344
  78. package/src/index.d.ts +0 -23
  79. package/src/index.d.ts.map +0 -1
  80. package/src/index.js +0 -28
  81. package/src/index.server.ts +0 -12
  82. package/src/index.tsx +0 -56
  83. package/src/init.d.ts +0 -33
  84. package/src/init.d.ts.map +0 -1
  85. package/src/init.js +0 -43
  86. package/src/init.tsx +0 -58
  87. package/src/types/index.d.ts +0 -80
  88. package/src/types/index.d.ts.map +0 -1
  89. package/src/types/index.js +0 -4
  90. package/src/types/index.ts +0 -84
  91. package/src/utils/fallback.d.ts +0 -27
  92. package/src/utils/fallback.d.ts.map +0 -1
  93. package/src/utils/fallback.js +0 -63
  94. package/src/utils/fallback.ts +0 -73
  95. package/src/utils/transforms.d.ts +0 -26
  96. package/src/utils/transforms.d.ts.map +0 -1
  97. package/src/utils/transforms.js +0 -38
  98. package/src/utils/transforms.ts +0 -54
  99. package/src/views/ImageManager.d.ts +0 -10
  100. package/src/views/ImageManager.d.ts.map +0 -1
  101. package/src/views/ImageManager.js +0 -9
  102. package/src/views/ImageManager.tsx +0 -30
@@ -1,93 +0,0 @@
1
- /**
2
- * Image Uploads API Route
3
- * Serves uploaded images for the plugin-images system
4
- */
5
-
6
- import { NextRequest, NextResponse } from 'next/server';
7
- import { readFile, unlink } from 'fs/promises';
8
- import path from 'path';
9
-
10
- export async function GET(
11
- request: NextRequest,
12
- { params }: { params: Promise<{ filename: string }> }
13
- ) {
14
- const { filename } = await params;
15
-
16
- // Security: Prevent directory traversal (only allow the filename)
17
- const sanitizedFilename = path.basename(filename);
18
- const uploadsDir = path.join(process.cwd(), 'data', 'uploads');
19
-
20
- // If filename doesn't have an extension, try common image extensions
21
- let filePath = path.join(uploadsDir, sanitizedFilename);
22
- const hasExtension = path.extname(sanitizedFilename).length > 0;
23
-
24
- if (!hasExtension) {
25
- // Try common image extensions
26
- const extensions = ['.png', '.jpg', '.jpeg', '.webp', '.gif', '.svg'];
27
- let found = false;
28
- for (const ext of extensions) {
29
- const testPath = filePath + ext;
30
- try {
31
- await readFile(testPath);
32
- filePath = testPath;
33
- found = true;
34
- break;
35
- } catch {
36
- // Continue to next extension
37
- }
38
- }
39
- if (!found) {
40
- // If no extension found, try the original filename
41
- filePath = path.join(uploadsDir, sanitizedFilename);
42
- }
43
- }
44
-
45
- try {
46
- const fileBuffer = await readFile(filePath);
47
-
48
- // Determine content type based on extension
49
- const ext = path.extname(filePath).toLowerCase();
50
- let contentType = 'application/octet-stream';
51
- if (ext === '.png') contentType = 'image/png';
52
- else if (ext === '.jpg' || ext === '.jpeg') contentType = 'image/jpeg';
53
- else if (ext === '.gif') contentType = 'image/gif';
54
- else if (ext === '.webp') contentType = 'image/webp';
55
- else if (ext === '.svg') contentType = 'image/svg+xml';
56
-
57
- return new NextResponse(fileBuffer, {
58
- headers: {
59
- 'Content-Type': contentType,
60
- 'Cache-Control': 'public, max-age=31536000, immutable',
61
- },
62
- });
63
- } catch (e) {
64
- // Don't log errors for missing files - it's expected for some requests
65
- return new NextResponse('File not found', { status: 404 });
66
- }
67
- }
68
-
69
- export async function DELETE(
70
- request: NextRequest,
71
- { params }: { params: Promise<{ filename: string }> }
72
- ) {
73
- const { filename } = await params;
74
-
75
- // Security: Prevent directory traversal (only allow the filename)
76
- const sanitizedFilename = path.basename(filename);
77
- const filePath = path.join(process.cwd(), 'data', 'uploads', sanitizedFilename);
78
-
79
- try {
80
- await unlink(filePath);
81
- return NextResponse.json({ success: true, message: 'File deleted' });
82
- } catch (e: any) {
83
- if (e.code === 'ENOENT') {
84
- return NextResponse.json({ error: 'File not found' }, { status: 404 });
85
- }
86
- console.error('File deletion error:', e);
87
- return NextResponse.json(
88
- { error: 'Failed to delete file', detail: e.message },
89
- { status: 500 }
90
- );
91
- }
92
- }
93
-
package/src/api-server.ts DELETED
@@ -1,11 +0,0 @@
1
- /**
2
- * Plugin Images - Server-Only API Exports
3
- * This file is only imported in server-side code (API routes)
4
- *
5
- * IMPORTANT: This file uses Node.js modules (fs, path, etc.) and should NEVER
6
- * be imported in client-side code. Only use in server-side API routes.
7
- */
8
-
9
- // Re-export everything from the API index
10
- export * from './api';
11
-
Binary file
@@ -1,11 +0,0 @@
1
- import React from 'react';
2
- export interface BackgroundImageProps {
3
- id: string;
4
- className?: string;
5
- style?: React.CSSProperties;
6
- children?: React.ReactNode;
7
- backgroundSize?: 'cover' | 'contain' | 'auto' | string;
8
- backgroundPosition?: string;
9
- }
10
- export declare function BackgroundImage({ id, className, style, children, backgroundSize, backgroundPosition, }: BackgroundImageProps): import("react/jsx-runtime").JSX.Element;
11
- //# sourceMappingURL=BackgroundImage.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BackgroundImage.d.ts","sourceRoot":"","sources":["BackgroundImage.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAInD,MAAM,WAAW,oBAAoB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,cAAc,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,CAAC;IACvD,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,wBAAgB,eAAe,CAAC,EAC5B,EAAE,EACF,SAAc,EACd,KAAU,EACV,QAAQ,EACR,cAAwB,EACxB,kBAA6B,GAChC,EAAE,oBAAoB,2CAqEtB"}
@@ -1,35 +0,0 @@
1
- 'use client';
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useState, useEffect } from 'react';
4
- import { Image } from './Image';
5
- import { Edit2 } from 'lucide-react';
6
- export function BackgroundImage({ id, className = '', style = {}, children, backgroundSize = 'cover', backgroundPosition = 'center', }) {
7
- var _a;
8
- const [isAdmin, setIsAdmin] = useState(false);
9
- const [isLoading, setIsLoading] = useState(true);
10
- useEffect(() => {
11
- const checkUser = async () => {
12
- var _a;
13
- try {
14
- const res = await fetch('/api/me');
15
- const data = await res.json();
16
- if (data.loggedIn && ['admin', 'dev'].includes((_a = data.user) === null || _a === void 0 ? void 0 : _a.role)) {
17
- setIsAdmin(true);
18
- }
19
- }
20
- catch (error) {
21
- console.error('Auth error:', error);
22
- }
23
- finally {
24
- setIsLoading(false);
25
- }
26
- };
27
- checkUser();
28
- }, []);
29
- const handleEditClick = (e) => {
30
- e.preventDefault();
31
- e.stopPropagation();
32
- window.dispatchEvent(new CustomEvent('open-image-editor', { detail: { id } }));
33
- };
34
- return (_jsxs("div", { className: `group relative overflow-hidden ${className}`, style: Object.assign(Object.assign({}, style), { minHeight: (_a = style.minHeight) !== null && _a !== void 0 ? _a : '300px' }), "data-background-id": id, children: [_jsx("div", { className: "absolute inset-0 z-0", children: _jsx(Image, { id: id, alt: "", fill: true, priority: true, className: "w-full h-full", objectFit: backgroundSize, objectPosition: backgroundPosition, editable: false }) }), _jsx("div", { className: "relative z-10 w-full h-full", children: children }), !isLoading && isAdmin && (_jsxs("button", { onClick: handleEditClick, className: "absolute bottom-8 left-8 z-50 flex items-center gap-3 px-6 py-3 bg-white dark:bg-neutral-800 text-neutral-900 dark:text-neutral-100 rounded-full shadow-2xl border border-neutral-200 dark:border-neutral-700 opacity-0 translate-y-4 group-hover:opacity-100 group-hover:translate-y-0 transition-all duration-500 ease-out", children: [_jsx(Edit2, { size: 16, className: "text-primary" }), _jsx("span", { className: "text-[11px] font-black uppercase tracking-widest", children: "Edit Background" })] }))] }));
35
- }
@@ -1,92 +0,0 @@
1
- 'use client';
2
-
3
- import React, { useState, useEffect } from 'react';
4
- import { Image } from './Image';
5
- import { Edit2 } from 'lucide-react';
6
-
7
- export interface BackgroundImageProps {
8
- id: string;
9
- className?: string;
10
- style?: React.CSSProperties;
11
- children?: React.ReactNode;
12
- backgroundSize?: 'cover' | 'contain' | 'auto' | string;
13
- backgroundPosition?: string;
14
- }
15
-
16
- export function BackgroundImage({
17
- id,
18
- className = '',
19
- style = {},
20
- children,
21
- backgroundSize = 'cover',
22
- backgroundPosition = 'center',
23
- }: BackgroundImageProps) {
24
- const [isAdmin, setIsAdmin] = useState(false);
25
- const [isLoading, setIsLoading] = useState(true);
26
-
27
- useEffect(() => {
28
- const checkUser = async () => {
29
- try {
30
- const res = await fetch('/api/me');
31
- const data = await res.json();
32
- if (data.loggedIn && ['admin', 'dev'].includes(data.user?.role)) {
33
- setIsAdmin(true);
34
- }
35
- } catch (error) {
36
- console.error('Auth error:', error);
37
- } finally {
38
- setIsLoading(false);
39
- }
40
- };
41
- checkUser();
42
- }, []);
43
-
44
- const handleEditClick = (e: React.MouseEvent) => {
45
- e.preventDefault();
46
- e.stopPropagation();
47
- window.dispatchEvent(new CustomEvent('open-image-editor', { detail: { id } }));
48
- };
49
-
50
- return (
51
- <div
52
- className={`group relative overflow-hidden ${className}`}
53
- style={{ ...style, minHeight: style.minHeight ?? '300px' }} // Ensure visibility
54
- data-background-id={id}
55
- >
56
- {/* 1. THE BACKGROUND LAYER
57
- We force 'fill' and 'w-full h-full' to ensure the internal
58
- Image component triggers its 'shouldFill' logic correctly.
59
- */}
60
- <div className="absolute inset-0 z-0">
61
- <Image
62
- id={id}
63
- alt=""
64
- fill
65
- priority
66
- className="w-full h-full"
67
- objectFit={backgroundSize as any}
68
- objectPosition={backgroundPosition}
69
- editable={false}
70
- />
71
- </div>
72
-
73
- {/* 2. CONTENT LAYER */}
74
- <div className="relative z-10 w-full h-full">
75
- {children}
76
- </div>
77
-
78
- {/* 3. ADMIN UI */}
79
- {!isLoading && isAdmin && (
80
- <button
81
- onClick={handleEditClick}
82
- className="absolute bottom-8 left-8 z-50 flex items-center gap-3 px-6 py-3 bg-white dark:bg-neutral-800 text-neutral-900 dark:text-neutral-100 rounded-full shadow-2xl border border-neutral-200 dark:border-neutral-700 opacity-0 translate-y-4 group-hover:opacity-100 group-hover:translate-y-0 transition-all duration-500 ease-out"
83
- >
84
- <Edit2 size={16} className="text-primary" />
85
- <span className="text-[11px] font-black uppercase tracking-widest">
86
- Edit Background
87
- </span>
88
- </button>
89
- )}
90
- </div>
91
- );
92
- }
@@ -1,9 +0,0 @@
1
- /**
2
- * Configuration utilities for GlobalImageEditor
3
- */
4
- import type { PluginConfig } from './types';
5
- /**
6
- * Read plugin configuration from window global
7
- */
8
- export declare function getPluginConfig(): PluginConfig;
9
- //# sourceMappingURL=config.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C;;GAEG;AACH,wBAAgB,eAAe,IAAI,YAAY,CAW9C"}
@@ -1,18 +0,0 @@
1
- /**
2
- * Configuration utilities for GlobalImageEditor
3
- */
4
- /**
5
- * Read plugin configuration from window global
6
- */
7
- export function getPluginConfig() {
8
- var _a;
9
- if (typeof window === 'undefined') {
10
- return { enabled: false };
11
- }
12
- const pluginProps = (_a = window.__JHITS_PLUGIN_PROPS__) === null || _a === void 0 ? void 0 : _a['plugin-images'];
13
- return {
14
- enabled: (pluginProps === null || pluginProps === void 0 ? void 0 : pluginProps.enabled) !== undefined ? pluginProps.enabled : true,
15
- className: pluginProps === null || pluginProps === void 0 ? void 0 : pluginProps.className,
16
- overlayClassName: pluginProps === null || pluginProps === void 0 ? void 0 : pluginProps.overlayClassName,
17
- };
18
- }
@@ -1,21 +0,0 @@
1
- /**
2
- * Configuration utilities for GlobalImageEditor
3
- */
4
-
5
- import type { PluginConfig } from './types';
6
-
7
- /**
8
- * Read plugin configuration from window global
9
- */
10
- export function getPluginConfig(): PluginConfig {
11
- if (typeof window === 'undefined') {
12
- return { enabled: false };
13
- }
14
-
15
- const pluginProps = (window as any).__JHITS_PLUGIN_PROPS__?.['plugin-images'];
16
- return {
17
- enabled: pluginProps?.enabled !== undefined ? pluginProps.enabled : true,
18
- className: pluginProps?.className,
19
- overlayClassName: pluginProps?.overlayClassName,
20
- };
21
- }
@@ -1,20 +0,0 @@
1
- /**
2
- * Event handlers for image changes and effects
3
- */
4
- import type { SelectedImage } from './types';
5
- import type { ImageMetadata } from '../../types';
6
- /**
7
- * Apply image changes to DOM and save to API
8
- */
9
- export declare function handleImageChange(image: ImageMetadata | null, selectedImage: SelectedImage, onClose: () => void): Promise<void>;
10
- /**
11
- * Handle brightness change
12
- * @param saveImmediately - If true, save to API immediately. If false, only update state/DOM (for editor preview)
13
- */
14
- export declare function handleBrightnessChange(brightness: number, selectedImage: SelectedImage, setSelectedImage: (image: SelectedImage) => void, saveImmediately?: boolean): Promise<void>;
15
- /**
16
- * Handle blur change
17
- * @param saveImmediately - If true, save to API immediately. If false, only update state/DOM (for editor preview)
18
- */
19
- export declare function handleBlurChange(blur: number, selectedImage: SelectedImage, setSelectedImage: (image: SelectedImage) => void, saveImmediately?: boolean): Promise<void>;
20
- //# sourceMappingURL=eventHandlers.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"eventHandlers.d.ts","sourceRoot":"","sources":["eventHandlers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGjD;;GAEG;AACH,wBAAsB,iBAAiB,CACnC,KAAK,EAAE,aAAa,GAAG,IAAI,EAC3B,aAAa,EAAE,aAAa,EAC5B,OAAO,EAAE,MAAM,IAAI,GACpB,OAAO,CAAC,IAAI,CAAC,CAiDf;AAoID;;;GAGG;AACH,wBAAsB,sBAAsB,CACxC,UAAU,EAAE,MAAM,EAClB,aAAa,EAAE,aAAa,EAC5B,gBAAgB,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,EAChD,eAAe,GAAE,OAAc,GAChC,OAAO,CAAC,IAAI,CAAC,CAyBf;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAClC,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,aAAa,EAC5B,gBAAgB,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,EAChD,eAAe,GAAE,OAAc,GAChC,OAAO,CAAC,IAAI,CAAC,CAyBf"}
@@ -1,206 +0,0 @@
1
- /**
2
- * Event handlers for image changes and effects
3
- */
4
- import { getFilename, saveTransformToAPI, normalizePosition } from './saveLogic';
5
- /**
6
- * Apply image changes to DOM and save to API
7
- */
8
- export async function handleImageChange(image, selectedImage, onClose) {
9
- var _a;
10
- if (!image)
11
- return;
12
- const { element } = selectedImage;
13
- const semanticId = element.getAttribute('data-image-id') ||
14
- element.getAttribute('data-background-image-id');
15
- if (!semanticId) {
16
- console.error('[GlobalImageEditor] No semantic ID found for image');
17
- return;
18
- }
19
- // Extract filename from image URL or use image.id
20
- const filename = ((_a = image.url.split('/').pop()) === null || _a === void 0 ? void 0 : _a.split('?')[0]) || image.id;
21
- const normalizedPositionX = normalizePosition(selectedImage.positionX);
22
- const normalizedPositionY = normalizePosition(selectedImage.positionY);
23
- // Save the mapping between semantic ID and filename, including effects and transforms
24
- await saveTransformToAPI(semanticId, filename, selectedImage.scale, normalizedPositionX, normalizedPositionY, selectedImage.brightness, selectedImage.blur);
25
- // Update image src immediately - handle background images differently
26
- if (selectedImage.isBackground) {
27
- updateBackgroundImage(element, image.url, selectedImage, normalizedPositionX, normalizedPositionY);
28
- }
29
- else {
30
- updateRegularImage(element, image.url, semanticId, selectedImage, normalizedPositionX, normalizedPositionY);
31
- }
32
- // Dispatch a custom event to notify Image components to re-resolve
33
- window.dispatchEvent(new CustomEvent('image-mapping-updated', {
34
- detail: {
35
- id: semanticId,
36
- filename,
37
- brightness: selectedImage.brightness,
38
- blur: selectedImage.blur,
39
- scale: selectedImage.scale,
40
- positionX: selectedImage.positionX,
41
- positionY: selectedImage.positionY,
42
- }
43
- }));
44
- onClose();
45
- }
46
- /**
47
- * Update background image element
48
- */
49
- function updateBackgroundImage(element, imageUrl, selectedImage, normalizedPositionX, normalizedPositionY) {
50
- // For background images, update the nested Image component
51
- const imgWrapper = element.querySelector('[data-image-id]');
52
- if (imgWrapper) {
53
- const img = imgWrapper.querySelector('img');
54
- if (img) {
55
- img.src = imageUrl;
56
- img.setAttribute('data-edited-src', imageUrl);
57
- img.style.transform = `scale(${selectedImage.scale}) translate(${normalizedPositionX}%, ${normalizedPositionY}%)`;
58
- img.style.transformOrigin = 'center center';
59
- }
60
- }
61
- else {
62
- // Fallback: update background-image style if no nested Image component
63
- const bgImage = window.getComputedStyle(element).backgroundImage;
64
- if (bgImage && bgImage !== 'none') {
65
- element.style.backgroundImage = `url(${imageUrl})`;
66
- }
67
- }
68
- // Store attributes on the background container
69
- const semanticId = element.getAttribute('data-image-id') || element.getAttribute('data-background-image-id') || '';
70
- element.setAttribute('data-background-image-id', semanticId);
71
- element.setAttribute('data-edited-src', imageUrl);
72
- element.setAttribute('data-brightness', selectedImage.brightness.toString());
73
- element.setAttribute('data-blur', selectedImage.blur.toString());
74
- element.setAttribute('data-scale', selectedImage.scale.toString());
75
- element.setAttribute('data-position-x', normalizedPositionX.toString());
76
- element.setAttribute('data-position-y', normalizedPositionY.toString());
77
- // Apply filter to the wrapper element
78
- if (selectedImage.brightness !== 100 || selectedImage.blur !== 0) {
79
- element.style.filter = `brightness(${selectedImage.brightness}%) blur(${selectedImage.blur}px)`;
80
- }
81
- else {
82
- element.style.filter = '';
83
- }
84
- }
85
- /**
86
- * Update regular image element
87
- */
88
- function updateRegularImage(element, imageUrl, semanticId, selectedImage, normalizedPositionX, normalizedPositionY) {
89
- if (element.tagName === 'IMG') {
90
- element.src = imageUrl;
91
- element.setAttribute('data-edited-src', imageUrl);
92
- element.setAttribute('data-image-id', semanticId);
93
- element.setAttribute('data-brightness', selectedImage.brightness.toString());
94
- element.setAttribute('data-blur', selectedImage.blur.toString());
95
- // Apply filter
96
- if (selectedImage.brightness !== 100 || selectedImage.blur !== 0) {
97
- element.style.filter = `brightness(${selectedImage.brightness}%) blur(${selectedImage.blur}px)`;
98
- }
99
- else {
100
- element.style.filter = '';
101
- }
102
- }
103
- else {
104
- // Next.js Image wrapper - find the actual img element
105
- const img = element.querySelector('img');
106
- if (img) {
107
- img.src = imageUrl;
108
- img.setAttribute('data-edited-src', imageUrl);
109
- img.style.transform = `scale(${selectedImage.scale}) translate(${normalizedPositionX}%, ${normalizedPositionY}%)`;
110
- img.style.transformOrigin = 'center center';
111
- }
112
- element.setAttribute('data-image-id', semanticId);
113
- element.setAttribute('data-edited-src', imageUrl);
114
- element.setAttribute('data-brightness', selectedImage.brightness.toString());
115
- element.setAttribute('data-blur', selectedImage.blur.toString());
116
- element.setAttribute('data-scale', selectedImage.scale.toString());
117
- element.setAttribute('data-position-x', normalizedPositionX.toString());
118
- element.setAttribute('data-position-y', normalizedPositionY.toString());
119
- // Apply filter to wrapper
120
- if (selectedImage.brightness !== 100 || selectedImage.blur !== 0) {
121
- element.style.filter = `brightness(${selectedImage.brightness}%) blur(${selectedImage.blur}px)`;
122
- }
123
- else {
124
- element.style.filter = '';
125
- }
126
- }
127
- }
128
- /**
129
- * Get filename from element for saving effects
130
- */
131
- async function getFilenameFromElement(semanticId, selectedImage) {
132
- var _a, _b;
133
- const filename = await getFilename(semanticId, selectedImage);
134
- if (filename)
135
- return filename;
136
- const { element } = selectedImage;
137
- if (selectedImage.isBackground) {
138
- const bgImage = window.getComputedStyle(element).backgroundImage;
139
- const urlMatch = bgImage.match(/url\(['"]?([^'"]+)['"]?\)/);
140
- if (urlMatch && urlMatch[1]) {
141
- return ((_a = urlMatch[1].split('/api/uploads/')[1]) === null || _a === void 0 ? void 0 : _a.split('?')[0]) || semanticId;
142
- }
143
- }
144
- else {
145
- let imgSrc = null;
146
- if (element instanceof HTMLImageElement && element.src) {
147
- imgSrc = element.src;
148
- }
149
- else {
150
- const img = element.querySelector('img');
151
- if (img === null || img === void 0 ? void 0 : img.src) {
152
- imgSrc = img.src;
153
- }
154
- }
155
- if (imgSrc) {
156
- return ((_b = imgSrc.split('/api/uploads/')[1]) === null || _b === void 0 ? void 0 : _b.split('?')[0]) || semanticId;
157
- }
158
- }
159
- return semanticId;
160
- }
161
- /**
162
- * Handle brightness change
163
- * @param saveImmediately - If true, save to API immediately. If false, only update state/DOM (for editor preview)
164
- */
165
- export async function handleBrightnessChange(brightness, selectedImage, setSelectedImage, saveImmediately = true) {
166
- const { element } = selectedImage;
167
- const semanticId = element.getAttribute('data-image-id') ||
168
- element.getAttribute('data-background-image-id');
169
- if (!semanticId)
170
- return;
171
- const currentFilter = element.style.filter || '';
172
- const blurMatch = currentFilter.match(/blur\((\d+)px\)/);
173
- const blur = blurMatch ? parseInt(blurMatch[1]) : selectedImage.blur;
174
- // Update the selectedImage state
175
- setSelectedImage(Object.assign(Object.assign({}, selectedImage), { brightness }));
176
- element.style.filter = `brightness(${brightness}%) blur(${blur}px)`;
177
- element.setAttribute('data-brightness', brightness.toString());
178
- // Save the effect immediately only if requested (not when in editor)
179
- if (saveImmediately) {
180
- const filename = await getFilenameFromElement(semanticId, selectedImage);
181
- await saveTransformToAPI(semanticId, filename, selectedImage.scale, selectedImage.positionX, selectedImage.positionY, brightness, blur);
182
- }
183
- }
184
- /**
185
- * Handle blur change
186
- * @param saveImmediately - If true, save to API immediately. If false, only update state/DOM (for editor preview)
187
- */
188
- export async function handleBlurChange(blur, selectedImage, setSelectedImage, saveImmediately = true) {
189
- const { element } = selectedImage;
190
- const semanticId = element.getAttribute('data-image-id') ||
191
- element.getAttribute('data-background-image-id');
192
- if (!semanticId)
193
- return;
194
- const currentFilter = element.style.filter || '';
195
- const brightnessMatch = currentFilter.match(/brightness\((\d+)%\)/);
196
- const brightness = brightnessMatch ? parseInt(brightnessMatch[1]) : selectedImage.brightness;
197
- // Update the selectedImage state
198
- setSelectedImage(Object.assign(Object.assign({}, selectedImage), { blur }));
199
- element.style.filter = `brightness(${brightness}%) blur(${blur}px)`;
200
- element.setAttribute('data-blur', blur.toString());
201
- // Save the effect immediately only if requested (not when in editor)
202
- if (saveImmediately) {
203
- const filename = await getFilenameFromElement(semanticId, selectedImage);
204
- await saveTransformToAPI(semanticId, filename, selectedImage.scale, selectedImage.positionX, selectedImage.positionY, brightness, blur);
205
- }
206
- }