@windrun-huaiin/third-ui 10.1.2 → 11.0.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/LICENSE +1 -1
- package/dist/clerk/fingerprint/fingerprint-client.js +2 -2
- package/dist/clerk/fingerprint/fingerprint-client.mjs +3 -3
- package/dist/clerk/fingerprint/fingerprint-shared.d.ts +1 -0
- package/dist/clerk/fingerprint/fingerprint-shared.js +2 -0
- package/dist/clerk/fingerprint/fingerprint-shared.mjs +2 -1
- package/dist/clerk/fingerprint/index.js +1 -0
- package/dist/clerk/fingerprint/index.mjs +1 -1
- package/dist/clerk/fingerprint/server.js +1 -0
- package/dist/clerk/fingerprint/server.mjs +1 -1
- package/dist/clerk/fingerprint/use-fingerprint.js +2 -1
- package/dist/clerk/fingerprint/use-fingerprint.mjs +2 -1
- package/package.json +3 -3
- package/src/clerk/fingerprint/fingerprint-client.ts +3 -2
- package/src/clerk/fingerprint/fingerprint-shared.ts +1 -0
- package/src/clerk/fingerprint/use-fingerprint.ts +2 -0
- package/dist/main/gallery-interactive.d.ts +0 -18
- package/dist/main/gallery-interactive.js +0 -138
- package/dist/main/gallery-interactive.mjs +0 -136
- package/dist/main/gallery.d.ts +0 -7
- package/dist/main/gallery.js +0 -43
- package/dist/main/gallery.mjs +0 -41
package/LICENSE
CHANGED
|
@@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
18
18
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
19
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
20
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
21
|
+
SOFTWARE.
|
|
@@ -118,7 +118,7 @@ function createFingerprintHeaders() {
|
|
|
118
118
|
return tslib_es6.__awaiter(this, void 0, void 0, function* () {
|
|
119
119
|
const fingerprintId = yield getOrGenerateFingerprintId();
|
|
120
120
|
return {
|
|
121
|
-
FINGERPRINT_HEADER_NAME: fingerprintId,
|
|
121
|
+
[fingerprintShared.FINGERPRINT_HEADER_NAME]: fingerprintId,
|
|
122
122
|
};
|
|
123
123
|
});
|
|
124
124
|
}
|
|
@@ -134,7 +134,7 @@ function useFingerprintHeaders() {
|
|
|
134
134
|
function createFingerprintFetch() {
|
|
135
135
|
return (url, init) => tslib_es6.__awaiter(this, void 0, void 0, function* () {
|
|
136
136
|
const fingerprintHeaders = yield createFingerprintHeaders();
|
|
137
|
-
const headers = Object.assign(Object.assign({}, fingerprintHeaders), ((init === null || init === void 0 ? void 0 : init.headers) || {}));
|
|
137
|
+
const headers = Object.assign(Object.assign(Object.assign({}, fingerprintHeaders), { [fingerprintShared.FINGERPRINT_SOURCE_REFER]: document.referrer || '' }), ((init === null || init === void 0 ? void 0 : init.headers) || {}));
|
|
138
138
|
return fetch(url, Object.assign(Object.assign({}, init), { headers }));
|
|
139
139
|
});
|
|
140
140
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { __awaiter } from '../../node_modules/.pnpm/@rollup_plugin-typescript@12.1.4_rollup@4.46.2_tslib@2.8.1_typescript@5.9.3/node_modules/tslib/tslib.es6.mjs';
|
|
2
2
|
import index from '../../node_modules/.pnpm/@fingerprintjs_fingerprintjs@4.6.2/node_modules/@fingerprintjs/fingerprintjs/dist/fp.esm.mjs';
|
|
3
|
-
import { isValidFingerprintId, FINGERPRINT_STORAGE_KEY, FINGERPRINT_COOKIE_NAME } from './fingerprint-shared.mjs';
|
|
3
|
+
import { isValidFingerprintId, FINGERPRINT_STORAGE_KEY, FINGERPRINT_COOKIE_NAME, FINGERPRINT_HEADER_NAME, FINGERPRINT_SOURCE_REFER } from './fingerprint-shared.mjs';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Fingerprint Client Utilities
|
|
@@ -116,7 +116,7 @@ function createFingerprintHeaders() {
|
|
|
116
116
|
return __awaiter(this, void 0, void 0, function* () {
|
|
117
117
|
const fingerprintId = yield getOrGenerateFingerprintId();
|
|
118
118
|
return {
|
|
119
|
-
FINGERPRINT_HEADER_NAME: fingerprintId,
|
|
119
|
+
[FINGERPRINT_HEADER_NAME]: fingerprintId,
|
|
120
120
|
};
|
|
121
121
|
});
|
|
122
122
|
}
|
|
@@ -132,7 +132,7 @@ function useFingerprintHeaders() {
|
|
|
132
132
|
function createFingerprintFetch() {
|
|
133
133
|
return (url, init) => __awaiter(this, void 0, void 0, function* () {
|
|
134
134
|
const fingerprintHeaders = yield createFingerprintHeaders();
|
|
135
|
-
const headers = Object.assign(Object.assign({}, fingerprintHeaders), ((init === null || init === void 0 ? void 0 : init.headers) || {}));
|
|
135
|
+
const headers = Object.assign(Object.assign(Object.assign({}, fingerprintHeaders), { [FINGERPRINT_SOURCE_REFER]: document.referrer || '' }), ((init === null || init === void 0 ? void 0 : init.headers) || {}));
|
|
136
136
|
return fetch(url, Object.assign(Object.assign({}, init), { headers }));
|
|
137
137
|
});
|
|
138
138
|
}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
export declare const FINGERPRINT_STORAGE_KEY = "__x_fingerprint_id";
|
|
6
6
|
export declare const FINGERPRINT_HEADER_NAME = "x-fingerprint-id-v8";
|
|
7
7
|
export declare const FINGERPRINT_COOKIE_NAME = "__x_fingerprint_id";
|
|
8
|
+
export declare const FINGERPRINT_SOURCE_REFER = "x-source-ref";
|
|
8
9
|
/**
|
|
9
10
|
* 验证fingerprint ID格式
|
|
10
11
|
* 可以在客户端和服务端使用
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
const FINGERPRINT_STORAGE_KEY = '__x_fingerprint_id';
|
|
9
9
|
const FINGERPRINT_HEADER_NAME = 'x-fingerprint-id-v8';
|
|
10
10
|
const FINGERPRINT_COOKIE_NAME = '__x_fingerprint_id';
|
|
11
|
+
const FINGERPRINT_SOURCE_REFER = 'x-source-ref';
|
|
11
12
|
/**
|
|
12
13
|
* 验证fingerprint ID格式
|
|
13
14
|
* 可以在客户端和服务端使用
|
|
@@ -31,5 +32,6 @@ const FINGERPRINT_CONSTANTS = {
|
|
|
31
32
|
exports.FINGERPRINT_CONSTANTS = FINGERPRINT_CONSTANTS;
|
|
32
33
|
exports.FINGERPRINT_COOKIE_NAME = FINGERPRINT_COOKIE_NAME;
|
|
33
34
|
exports.FINGERPRINT_HEADER_NAME = FINGERPRINT_HEADER_NAME;
|
|
35
|
+
exports.FINGERPRINT_SOURCE_REFER = FINGERPRINT_SOURCE_REFER;
|
|
34
36
|
exports.FINGERPRINT_STORAGE_KEY = FINGERPRINT_STORAGE_KEY;
|
|
35
37
|
exports.isValidFingerprintId = isValidFingerprintId;
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
const FINGERPRINT_STORAGE_KEY = '__x_fingerprint_id';
|
|
7
7
|
const FINGERPRINT_HEADER_NAME = 'x-fingerprint-id-v8';
|
|
8
8
|
const FINGERPRINT_COOKIE_NAME = '__x_fingerprint_id';
|
|
9
|
+
const FINGERPRINT_SOURCE_REFER = 'x-source-ref';
|
|
9
10
|
/**
|
|
10
11
|
* 验证fingerprint ID格式
|
|
11
12
|
* 可以在客户端和服务端使用
|
|
@@ -26,4 +27,4 @@ const FINGERPRINT_CONSTANTS = {
|
|
|
26
27
|
COOKIE_NAME: FINGERPRINT_COOKIE_NAME,
|
|
27
28
|
};
|
|
28
29
|
|
|
29
|
-
export { FINGERPRINT_CONSTANTS, FINGERPRINT_COOKIE_NAME, FINGERPRINT_HEADER_NAME, FINGERPRINT_STORAGE_KEY, isValidFingerprintId };
|
|
30
|
+
export { FINGERPRINT_CONSTANTS, FINGERPRINT_COOKIE_NAME, FINGERPRINT_HEADER_NAME, FINGERPRINT_SOURCE_REFER, FINGERPRINT_STORAGE_KEY, isValidFingerprintId };
|
|
@@ -11,6 +11,7 @@ var fingerprintProvider = require('./fingerprint-provider.js');
|
|
|
11
11
|
exports.FINGERPRINT_CONSTANTS = fingerprintShared.FINGERPRINT_CONSTANTS;
|
|
12
12
|
exports.FINGERPRINT_COOKIE_NAME = fingerprintShared.FINGERPRINT_COOKIE_NAME;
|
|
13
13
|
exports.FINGERPRINT_HEADER_NAME = fingerprintShared.FINGERPRINT_HEADER_NAME;
|
|
14
|
+
exports.FINGERPRINT_SOURCE_REFER = fingerprintShared.FINGERPRINT_SOURCE_REFER;
|
|
14
15
|
exports.FINGERPRINT_STORAGE_KEY = fingerprintShared.FINGERPRINT_STORAGE_KEY;
|
|
15
16
|
exports.isValidFingerprintId = fingerprintShared.isValidFingerprintId;
|
|
16
17
|
exports.clearFingerprintId = fingerprintClient.clearFingerprintId;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
export { FINGERPRINT_CONSTANTS, FINGERPRINT_COOKIE_NAME, FINGERPRINT_HEADER_NAME, FINGERPRINT_STORAGE_KEY, isValidFingerprintId } from './fingerprint-shared.mjs';
|
|
2
|
+
export { FINGERPRINT_CONSTANTS, FINGERPRINT_COOKIE_NAME, FINGERPRINT_HEADER_NAME, FINGERPRINT_SOURCE_REFER, FINGERPRINT_STORAGE_KEY, isValidFingerprintId } from './fingerprint-shared.mjs';
|
|
3
3
|
export { clearFingerprintId, createFingerprintFetch, createFingerprintHeaders, generateFingerprintId, getFingerprintId, getOrGenerateFingerprintId, setFingerprintId, useFingerprintHeaders } from './fingerprint-client.mjs';
|
|
4
4
|
export { useFingerprint } from './use-fingerprint.mjs';
|
|
5
5
|
export { FingerprintProvider, FingerprintStatus, useFingerprintContext, useFingerprintContextSafe, withFingerprint } from './fingerprint-provider.mjs';
|
|
@@ -8,6 +8,7 @@ var fingerprintServer = require('./fingerprint-server.js');
|
|
|
8
8
|
exports.FINGERPRINT_CONSTANTS = fingerprintShared.FINGERPRINT_CONSTANTS;
|
|
9
9
|
exports.FINGERPRINT_COOKIE_NAME = fingerprintShared.FINGERPRINT_COOKIE_NAME;
|
|
10
10
|
exports.FINGERPRINT_HEADER_NAME = fingerprintShared.FINGERPRINT_HEADER_NAME;
|
|
11
|
+
exports.FINGERPRINT_SOURCE_REFER = fingerprintShared.FINGERPRINT_SOURCE_REFER;
|
|
11
12
|
exports.FINGERPRINT_STORAGE_KEY = fingerprintShared.FINGERPRINT_STORAGE_KEY;
|
|
12
13
|
exports.isValidFingerprintId = fingerprintShared.isValidFingerprintId;
|
|
13
14
|
exports.extractFingerprintFromNextRequest = fingerprintServer.extractFingerprintFromNextRequest;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { FINGERPRINT_CONSTANTS, FINGERPRINT_COOKIE_NAME, FINGERPRINT_HEADER_NAME, FINGERPRINT_STORAGE_KEY, isValidFingerprintId } from './fingerprint-shared.mjs';
|
|
1
|
+
export { FINGERPRINT_CONSTANTS, FINGERPRINT_COOKIE_NAME, FINGERPRINT_HEADER_NAME, FINGERPRINT_SOURCE_REFER, FINGERPRINT_STORAGE_KEY, isValidFingerprintId } from './fingerprint-shared.mjs';
|
|
2
2
|
export { extractFingerprintFromNextRequest, extractFingerprintFromNextStores, extractFingerprintId, generateServerFingerprintId } from './fingerprint-server.mjs';
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
var tslib_es6 = require('../../node_modules/.pnpm/@rollup_plugin-typescript@12.1.4_rollup@4.46.2_tslib@2.8.1_typescript@5.9.3/node_modules/tslib/tslib.es6.js');
|
|
5
5
|
var React = require('react');
|
|
6
6
|
var fingerprintClient = require('./fingerprint-client.js');
|
|
7
|
+
var fingerprintShared = require('./fingerprint-shared.js');
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Hook for managing fingerprint ID and anonymous user data
|
|
@@ -64,7 +65,7 @@ function useFingerprint(config) {
|
|
|
64
65
|
const fingerprintHeaders = yield fingerprintClient.createFingerprintHeaders();
|
|
65
66
|
const response = yield fetch(config.apiEndpoint, {
|
|
66
67
|
method: 'POST',
|
|
67
|
-
headers: Object.assign({ 'Content-Type': 'application/json' }, fingerprintHeaders),
|
|
68
|
+
headers: Object.assign({ 'Content-Type': 'application/json', [fingerprintShared.FINGERPRINT_SOURCE_REFER]: document.referrer || '' }, fingerprintHeaders),
|
|
68
69
|
body: JSON.stringify({ fingerprintId }),
|
|
69
70
|
});
|
|
70
71
|
if (!response.ok) {
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { __awaiter } from '../../node_modules/.pnpm/@rollup_plugin-typescript@12.1.4_rollup@4.46.2_tslib@2.8.1_typescript@5.9.3/node_modules/tslib/tslib.es6.mjs';
|
|
3
3
|
import { useState, useCallback, useEffect } from 'react';
|
|
4
4
|
import { getOrGenerateFingerprintId, createFingerprintHeaders } from './fingerprint-client.mjs';
|
|
5
|
+
import { FINGERPRINT_SOURCE_REFER } from './fingerprint-shared.mjs';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Hook for managing fingerprint ID and anonymous user data
|
|
@@ -62,7 +63,7 @@ function useFingerprint(config) {
|
|
|
62
63
|
const fingerprintHeaders = yield createFingerprintHeaders();
|
|
63
64
|
const response = yield fetch(config.apiEndpoint, {
|
|
64
65
|
method: 'POST',
|
|
65
|
-
headers: Object.assign({ 'Content-Type': 'application/json' }, fingerprintHeaders),
|
|
66
|
+
headers: Object.assign({ 'Content-Type': 'application/json', [FINGERPRINT_SOURCE_REFER]: document.referrer || '' }, fingerprintHeaders),
|
|
66
67
|
body: JSON.stringify({ fingerprintId }),
|
|
67
68
|
});
|
|
68
69
|
if (!response.ok) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@windrun-huaiin/third-ui",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "11.0.0",
|
|
4
4
|
"description": "Third-party integrated UI components for windrun-huaiin projects",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -81,8 +81,8 @@
|
|
|
81
81
|
"react-medium-image-zoom": "^5.2.14",
|
|
82
82
|
"swiper": "^12.0.3",
|
|
83
83
|
"zod": "^4.1.12",
|
|
84
|
-
"@windrun-huaiin/base-ui": "^
|
|
85
|
-
"@windrun-huaiin/lib": "^
|
|
84
|
+
"@windrun-huaiin/base-ui": "^11.0.0",
|
|
85
|
+
"@windrun-huaiin/lib": "^11.0.0"
|
|
86
86
|
},
|
|
87
87
|
"peerDependencies": {
|
|
88
88
|
"clsx": "^2.1.1",
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import FingerprintJS from '@fingerprintjs/fingerprintjs';
|
|
8
|
-
import {
|
|
8
|
+
import { FINGERPRINT_COOKIE_NAME, FINGERPRINT_HEADER_NAME, FINGERPRINT_SOURCE_REFER, FINGERPRINT_STORAGE_KEY, isValidFingerprintId } from './fingerprint-shared';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* 检查浏览器存储(localStorage 和 cookie)中的指纹 ID
|
|
@@ -128,7 +128,7 @@ export async function getOrGenerateFingerprintId(): Promise<string> {
|
|
|
128
128
|
export async function createFingerprintHeaders(): Promise<Record<string, string>> {
|
|
129
129
|
const fingerprintId = await getOrGenerateFingerprintId();
|
|
130
130
|
return {
|
|
131
|
-
FINGERPRINT_HEADER_NAME: fingerprintId,
|
|
131
|
+
[FINGERPRINT_HEADER_NAME]: fingerprintId,
|
|
132
132
|
};
|
|
133
133
|
}
|
|
134
134
|
|
|
@@ -147,6 +147,7 @@ export function createFingerprintFetch() {
|
|
|
147
147
|
const fingerprintHeaders = await createFingerprintHeaders();
|
|
148
148
|
const headers = {
|
|
149
149
|
...fingerprintHeaders,
|
|
150
|
+
[FINGERPRINT_SOURCE_REFER]: document.referrer || '',
|
|
150
151
|
...(init?.headers || {}),
|
|
151
152
|
};
|
|
152
153
|
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
export const FINGERPRINT_STORAGE_KEY = '__x_fingerprint_id';
|
|
8
8
|
export const FINGERPRINT_HEADER_NAME = 'x-fingerprint-id-v8';
|
|
9
9
|
export const FINGERPRINT_COOKIE_NAME = '__x_fingerprint_id';
|
|
10
|
+
export const FINGERPRINT_SOURCE_REFER = 'x-source-ref';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* 验证fingerprint ID格式
|
|
@@ -12,6 +12,7 @@ import type {
|
|
|
12
12
|
XSubscription,
|
|
13
13
|
XUser
|
|
14
14
|
} from './types';
|
|
15
|
+
import { FINGERPRINT_SOURCE_REFER } from './fingerprint-shared'
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* Hook for managing fingerprint ID and anonymous user data
|
|
@@ -77,6 +78,7 @@ export function useFingerprint(config: FingerprintConfig): UseFingerprintResult
|
|
|
77
78
|
method: 'POST',
|
|
78
79
|
headers: {
|
|
79
80
|
'Content-Type': 'application/json',
|
|
81
|
+
[FINGERPRINT_SOURCE_REFER]: document.referrer || '',
|
|
80
82
|
...fingerprintHeaders,
|
|
81
83
|
},
|
|
82
84
|
body: JSON.stringify({ fingerprintId }),
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
interface GalleryItem {
|
|
2
|
-
id: string;
|
|
3
|
-
url: string;
|
|
4
|
-
altMsg: string;
|
|
5
|
-
}
|
|
6
|
-
interface GalleryData {
|
|
7
|
-
titleL: string;
|
|
8
|
-
eyesOn: string;
|
|
9
|
-
titleR: string;
|
|
10
|
-
description: string;
|
|
11
|
-
items: GalleryItem[];
|
|
12
|
-
defaultImgUrl: string;
|
|
13
|
-
downloadPrefix: string;
|
|
14
|
-
}
|
|
15
|
-
export declare function GalleryInteractive({ data }: {
|
|
16
|
-
data: GalleryData;
|
|
17
|
-
}): null;
|
|
18
|
-
export {};
|
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
'use strict';
|
|
3
|
-
|
|
4
|
-
var tslib_es6 = require('../node_modules/.pnpm/@rollup_plugin-typescript@12.1.4_rollup@4.46.2_tslib@2.8.1_typescript@5.9.3/node_modules/tslib/tslib.es6.js');
|
|
5
|
-
var React = require('react');
|
|
6
|
-
|
|
7
|
-
function GalleryInteractive({ data }) {
|
|
8
|
-
const [imageErrors, setImageErrors] = React.useState(new Set());
|
|
9
|
-
const [downloadingItems, setDownloadingItems] = React.useState(new Set());
|
|
10
|
-
// Get CDN proxy URL from environment
|
|
11
|
-
const cdnProxyUrl = process.env.NEXT_PUBLIC_STYLE_CDN_PROXY_URL;
|
|
12
|
-
React.useEffect(() => {
|
|
13
|
-
// Progressive enhancement: Add download functionality and error handling
|
|
14
|
-
data.items.forEach((item, index) => {
|
|
15
|
-
const downloadButton = document.querySelector(`[data-gallery-download="${item.id}"]`);
|
|
16
|
-
const imageElement = document.querySelector(`[data-gallery-image="${item.id}"]`);
|
|
17
|
-
if (downloadButton) {
|
|
18
|
-
const handleDownload = () => tslib_es6.__awaiter(this, void 0, void 0, function* () {
|
|
19
|
-
var _a;
|
|
20
|
-
// Prevent duplicate clicks
|
|
21
|
-
if (downloadingItems.has(item.id)) {
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
// Set download status
|
|
25
|
-
setDownloadingItems(prev => new Set(prev).add(item.id));
|
|
26
|
-
try {
|
|
27
|
-
if (!cdnProxyUrl) {
|
|
28
|
-
throw new Error('CDN proxy URL not configured');
|
|
29
|
-
}
|
|
30
|
-
// Use R2 proxy to download directly
|
|
31
|
-
const originalUrl = new URL(item.url);
|
|
32
|
-
const filename = originalUrl.pathname.substring(1);
|
|
33
|
-
// Build proxy download URL
|
|
34
|
-
const proxyUrl = `${cdnProxyUrl}/${encodeURIComponent(filename)}`;
|
|
35
|
-
// Extract file extension from URL
|
|
36
|
-
const urlExtension = (_a = item.url.split('.').pop()) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
37
|
-
let extension = '.webp';
|
|
38
|
-
if (urlExtension && ['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg'].includes(urlExtension)) {
|
|
39
|
-
extension = `.${urlExtension}`;
|
|
40
|
-
}
|
|
41
|
-
// Fetch file from proxy
|
|
42
|
-
const response = yield fetch(proxyUrl);
|
|
43
|
-
if (!response.ok) {
|
|
44
|
-
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
45
|
-
}
|
|
46
|
-
// Convert to blob
|
|
47
|
-
const blob = yield response.blob();
|
|
48
|
-
const blobUrl = URL.createObjectURL(blob);
|
|
49
|
-
// Create download link and trigger download
|
|
50
|
-
const a = document.createElement('a');
|
|
51
|
-
a.href = blobUrl;
|
|
52
|
-
a.download = `${data.downloadPrefix}-${index + 1}${extension}`;
|
|
53
|
-
a.style.display = 'none';
|
|
54
|
-
document.body.appendChild(a);
|
|
55
|
-
a.click();
|
|
56
|
-
// Clean up DOM elements and blob URL
|
|
57
|
-
setTimeout(() => {
|
|
58
|
-
document.body.removeChild(a);
|
|
59
|
-
URL.revokeObjectURL(blobUrl);
|
|
60
|
-
}, 100);
|
|
61
|
-
}
|
|
62
|
-
catch (error) {
|
|
63
|
-
console.error('Download failed:', error);
|
|
64
|
-
}
|
|
65
|
-
finally {
|
|
66
|
-
// Clear download status
|
|
67
|
-
setDownloadingItems(prev => {
|
|
68
|
-
const newSet = new Set(prev);
|
|
69
|
-
newSet.delete(item.id);
|
|
70
|
-
return newSet;
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
downloadButton.addEventListener('click', handleDownload);
|
|
75
|
-
}
|
|
76
|
-
if (imageElement) {
|
|
77
|
-
const handleImageError = () => {
|
|
78
|
-
setImageErrors(prev => new Set(prev).add(item.id));
|
|
79
|
-
// Update image src to default
|
|
80
|
-
imageElement.src = data.defaultImgUrl;
|
|
81
|
-
};
|
|
82
|
-
imageElement.addEventListener('error', handleImageError);
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
// Update download button states based on downloading status
|
|
86
|
-
const updateDownloadStates = () => {
|
|
87
|
-
data.items.forEach((item) => {
|
|
88
|
-
const downloadButton = document.querySelector(`[data-gallery-download="${item.id}"]`);
|
|
89
|
-
if (downloadButton) {
|
|
90
|
-
const isDownloading = downloadingItems.has(item.id);
|
|
91
|
-
if (isDownloading) {
|
|
92
|
-
downloadButton.disabled = true;
|
|
93
|
-
downloadButton.classList.add('bg-black/30', 'text-white/50');
|
|
94
|
-
downloadButton.classList.remove('bg-black/50', 'hover:bg-black/70', 'text-white/80', 'hover:text-white');
|
|
95
|
-
// Replace icon with spinner
|
|
96
|
-
downloadButton.innerHTML = `
|
|
97
|
-
<svg class="h-5 w-5 text-white animate-spin" fill="none" viewBox="0 0 24 24">
|
|
98
|
-
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
|
99
|
-
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
|
100
|
-
</svg>
|
|
101
|
-
`;
|
|
102
|
-
}
|
|
103
|
-
else {
|
|
104
|
-
downloadButton.disabled = false;
|
|
105
|
-
downloadButton.classList.remove('bg-black/30', 'text-white/50');
|
|
106
|
-
downloadButton.classList.add('bg-black/50', 'hover:bg-black/70', 'text-white/80', 'hover:text-white');
|
|
107
|
-
// Reset to download icon
|
|
108
|
-
downloadButton.innerHTML = `
|
|
109
|
-
<svg class="h-5 w-5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
110
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
|
|
111
|
-
</svg>
|
|
112
|
-
`;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
});
|
|
116
|
-
};
|
|
117
|
-
updateDownloadStates();
|
|
118
|
-
// Cleanup event listeners
|
|
119
|
-
return () => {
|
|
120
|
-
data.items.forEach((item) => {
|
|
121
|
-
var _a, _b;
|
|
122
|
-
const downloadButton = document.querySelector(`[data-gallery-download="${item.id}"]`);
|
|
123
|
-
const imageElement = document.querySelector(`[data-gallery-image="${item.id}"]`);
|
|
124
|
-
if (downloadButton) {
|
|
125
|
-
const newButton = downloadButton.cloneNode(true);
|
|
126
|
-
(_a = downloadButton.parentNode) === null || _a === void 0 ? void 0 : _a.replaceChild(newButton, downloadButton);
|
|
127
|
-
}
|
|
128
|
-
if (imageElement) {
|
|
129
|
-
const newImage = imageElement.cloneNode(true);
|
|
130
|
-
(_b = imageElement.parentNode) === null || _b === void 0 ? void 0 : _b.replaceChild(newImage, imageElement);
|
|
131
|
-
}
|
|
132
|
-
});
|
|
133
|
-
};
|
|
134
|
-
}, [data, downloadingItems, imageErrors, cdnProxyUrl]);
|
|
135
|
-
return null; // Progressive enhancement - no additional DOM rendering
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
exports.GalleryInteractive = GalleryInteractive;
|
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { __awaiter } from '../node_modules/.pnpm/@rollup_plugin-typescript@12.1.4_rollup@4.46.2_tslib@2.8.1_typescript@5.9.3/node_modules/tslib/tslib.es6.mjs';
|
|
3
|
-
import { useState, useEffect } from 'react';
|
|
4
|
-
|
|
5
|
-
function GalleryInteractive({ data }) {
|
|
6
|
-
const [imageErrors, setImageErrors] = useState(new Set());
|
|
7
|
-
const [downloadingItems, setDownloadingItems] = useState(new Set());
|
|
8
|
-
// Get CDN proxy URL from environment
|
|
9
|
-
const cdnProxyUrl = process.env.NEXT_PUBLIC_STYLE_CDN_PROXY_URL;
|
|
10
|
-
useEffect(() => {
|
|
11
|
-
// Progressive enhancement: Add download functionality and error handling
|
|
12
|
-
data.items.forEach((item, index) => {
|
|
13
|
-
const downloadButton = document.querySelector(`[data-gallery-download="${item.id}"]`);
|
|
14
|
-
const imageElement = document.querySelector(`[data-gallery-image="${item.id}"]`);
|
|
15
|
-
if (downloadButton) {
|
|
16
|
-
const handleDownload = () => __awaiter(this, void 0, void 0, function* () {
|
|
17
|
-
var _a;
|
|
18
|
-
// Prevent duplicate clicks
|
|
19
|
-
if (downloadingItems.has(item.id)) {
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
// Set download status
|
|
23
|
-
setDownloadingItems(prev => new Set(prev).add(item.id));
|
|
24
|
-
try {
|
|
25
|
-
if (!cdnProxyUrl) {
|
|
26
|
-
throw new Error('CDN proxy URL not configured');
|
|
27
|
-
}
|
|
28
|
-
// Use R2 proxy to download directly
|
|
29
|
-
const originalUrl = new URL(item.url);
|
|
30
|
-
const filename = originalUrl.pathname.substring(1);
|
|
31
|
-
// Build proxy download URL
|
|
32
|
-
const proxyUrl = `${cdnProxyUrl}/${encodeURIComponent(filename)}`;
|
|
33
|
-
// Extract file extension from URL
|
|
34
|
-
const urlExtension = (_a = item.url.split('.').pop()) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
35
|
-
let extension = '.webp';
|
|
36
|
-
if (urlExtension && ['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg'].includes(urlExtension)) {
|
|
37
|
-
extension = `.${urlExtension}`;
|
|
38
|
-
}
|
|
39
|
-
// Fetch file from proxy
|
|
40
|
-
const response = yield fetch(proxyUrl);
|
|
41
|
-
if (!response.ok) {
|
|
42
|
-
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
43
|
-
}
|
|
44
|
-
// Convert to blob
|
|
45
|
-
const blob = yield response.blob();
|
|
46
|
-
const blobUrl = URL.createObjectURL(blob);
|
|
47
|
-
// Create download link and trigger download
|
|
48
|
-
const a = document.createElement('a');
|
|
49
|
-
a.href = blobUrl;
|
|
50
|
-
a.download = `${data.downloadPrefix}-${index + 1}${extension}`;
|
|
51
|
-
a.style.display = 'none';
|
|
52
|
-
document.body.appendChild(a);
|
|
53
|
-
a.click();
|
|
54
|
-
// Clean up DOM elements and blob URL
|
|
55
|
-
setTimeout(() => {
|
|
56
|
-
document.body.removeChild(a);
|
|
57
|
-
URL.revokeObjectURL(blobUrl);
|
|
58
|
-
}, 100);
|
|
59
|
-
}
|
|
60
|
-
catch (error) {
|
|
61
|
-
console.error('Download failed:', error);
|
|
62
|
-
}
|
|
63
|
-
finally {
|
|
64
|
-
// Clear download status
|
|
65
|
-
setDownloadingItems(prev => {
|
|
66
|
-
const newSet = new Set(prev);
|
|
67
|
-
newSet.delete(item.id);
|
|
68
|
-
return newSet;
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
});
|
|
72
|
-
downloadButton.addEventListener('click', handleDownload);
|
|
73
|
-
}
|
|
74
|
-
if (imageElement) {
|
|
75
|
-
const handleImageError = () => {
|
|
76
|
-
setImageErrors(prev => new Set(prev).add(item.id));
|
|
77
|
-
// Update image src to default
|
|
78
|
-
imageElement.src = data.defaultImgUrl;
|
|
79
|
-
};
|
|
80
|
-
imageElement.addEventListener('error', handleImageError);
|
|
81
|
-
}
|
|
82
|
-
});
|
|
83
|
-
// Update download button states based on downloading status
|
|
84
|
-
const updateDownloadStates = () => {
|
|
85
|
-
data.items.forEach((item) => {
|
|
86
|
-
const downloadButton = document.querySelector(`[data-gallery-download="${item.id}"]`);
|
|
87
|
-
if (downloadButton) {
|
|
88
|
-
const isDownloading = downloadingItems.has(item.id);
|
|
89
|
-
if (isDownloading) {
|
|
90
|
-
downloadButton.disabled = true;
|
|
91
|
-
downloadButton.classList.add('bg-black/30', 'text-white/50');
|
|
92
|
-
downloadButton.classList.remove('bg-black/50', 'hover:bg-black/70', 'text-white/80', 'hover:text-white');
|
|
93
|
-
// Replace icon with spinner
|
|
94
|
-
downloadButton.innerHTML = `
|
|
95
|
-
<svg class="h-5 w-5 text-white animate-spin" fill="none" viewBox="0 0 24 24">
|
|
96
|
-
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
|
97
|
-
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
|
98
|
-
</svg>
|
|
99
|
-
`;
|
|
100
|
-
}
|
|
101
|
-
else {
|
|
102
|
-
downloadButton.disabled = false;
|
|
103
|
-
downloadButton.classList.remove('bg-black/30', 'text-white/50');
|
|
104
|
-
downloadButton.classList.add('bg-black/50', 'hover:bg-black/70', 'text-white/80', 'hover:text-white');
|
|
105
|
-
// Reset to download icon
|
|
106
|
-
downloadButton.innerHTML = `
|
|
107
|
-
<svg class="h-5 w-5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
108
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
|
|
109
|
-
</svg>
|
|
110
|
-
`;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
});
|
|
114
|
-
};
|
|
115
|
-
updateDownloadStates();
|
|
116
|
-
// Cleanup event listeners
|
|
117
|
-
return () => {
|
|
118
|
-
data.items.forEach((item) => {
|
|
119
|
-
var _a, _b;
|
|
120
|
-
const downloadButton = document.querySelector(`[data-gallery-download="${item.id}"]`);
|
|
121
|
-
const imageElement = document.querySelector(`[data-gallery-image="${item.id}"]`);
|
|
122
|
-
if (downloadButton) {
|
|
123
|
-
const newButton = downloadButton.cloneNode(true);
|
|
124
|
-
(_a = downloadButton.parentNode) === null || _a === void 0 ? void 0 : _a.replaceChild(newButton, downloadButton);
|
|
125
|
-
}
|
|
126
|
-
if (imageElement) {
|
|
127
|
-
const newImage = imageElement.cloneNode(true);
|
|
128
|
-
(_b = imageElement.parentNode) === null || _b === void 0 ? void 0 : _b.replaceChild(newImage, imageElement);
|
|
129
|
-
}
|
|
130
|
-
});
|
|
131
|
-
};
|
|
132
|
-
}, [data, downloadingItems, imageErrors, cdnProxyUrl]);
|
|
133
|
-
return null; // Progressive enhancement - no additional DOM rendering
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
export { GalleryInteractive };
|
package/dist/main/gallery.d.ts
DELETED
package/dist/main/gallery.js
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var tslib_es6 = require('../node_modules/.pnpm/@rollup_plugin-typescript@12.1.4_rollup@4.46.2_tslib@2.8.1_typescript@5.9.3/node_modules/tslib/tslib.es6.js');
|
|
4
|
-
var jsxRuntime = require('react/jsx-runtime');
|
|
5
|
-
var server = require('next-intl/server');
|
|
6
|
-
var utils = require('@windrun-huaiin/lib/utils');
|
|
7
|
-
var Image = require('next/image');
|
|
8
|
-
require('react');
|
|
9
|
-
require('@windrun-huaiin/base-ui/components/server');
|
|
10
|
-
require('./nprogress-bar.js');
|
|
11
|
-
require('@windrun-huaiin/base-ui/ui');
|
|
12
|
-
require('./rich-text-expert.js');
|
|
13
|
-
require('next/navigation');
|
|
14
|
-
var galleryInteractive = require('./gallery-interactive.js');
|
|
15
|
-
require('@clerk/nextjs');
|
|
16
|
-
require('./money-price/money-price-types.js');
|
|
17
|
-
require('next/link');
|
|
18
|
-
var swiperReact = require('../node_modules/.pnpm/swiper@12.0.3/node_modules/swiper/swiper-react.js');
|
|
19
|
-
var pagination = require('../node_modules/.pnpm/swiper@12.0.3/node_modules/swiper/modules/pagination.js');
|
|
20
|
-
var sectionLayout = require('./section-layout.js');
|
|
21
|
-
|
|
22
|
-
function Gallery(_a) {
|
|
23
|
-
return tslib_es6.__awaiter(this, arguments, void 0, function* ({ locale, sectionClassName, button }) {
|
|
24
|
-
const t = yield server.getTranslations({ locale, namespace: 'gallery' });
|
|
25
|
-
const galleryItems = t.raw('prompts');
|
|
26
|
-
const data = {
|
|
27
|
-
titleL: t('titleL'),
|
|
28
|
-
eyesOn: t('eyesOn'),
|
|
29
|
-
titleR: t('titleR'),
|
|
30
|
-
description: t('description'),
|
|
31
|
-
items: galleryItems.map((item, index) => ({
|
|
32
|
-
id: `gallery-item-${index}`,
|
|
33
|
-
url: item.url,
|
|
34
|
-
altMsg: item.altMsg
|
|
35
|
-
})),
|
|
36
|
-
defaultImgUrl: t.raw('defaultImgUrl'),
|
|
37
|
-
downloadPrefix: t('downloadPrefix')
|
|
38
|
-
};
|
|
39
|
-
return (jsxRuntime.jsxs("section", { id: "gallery", className: utils.cn(sectionLayout.responsiveSection, sectionClassName), children: [jsxRuntime.jsxs("h2", { className: "text-3xl md:text-4xl font-bold text-center mb-6", children: [data.titleL, " ", jsxRuntime.jsx("span", { className: "text-purple-500", children: data.eyesOn }), " ", data.titleR] }), jsxRuntime.jsx("p", { className: "text-center max-w-2xl mx-auto mb-16", children: data.description }), jsxRuntime.jsx("div", { className: "block sm:hidden", children: jsxRuntime.jsx(swiperReact.Swiper, { modules: [pagination], pagination: { clickable: true }, spaceBetween: 20, slidesPerView: 1, loop: true, className: "rounded-xl overflow-hidden", children: data.items.map((item, index) => (jsxRuntime.jsx(swiperReact.SwiperSlide, { children: jsxRuntime.jsxs("div", { className: "relative aspect-square bg-gray-100", children: [jsxRuntime.jsx(Image, { src: item.url, alt: item.altMsg, fill: true, className: "object-cover", "data-gallery-image": item.id }), jsxRuntime.jsx("button", { className: "absolute bottom-4 right-4 p-3 rounded-full bg-black/60 hover:bg-black/80 text-white transition-all z-10", "data-gallery-download": item.id, "aria-label": `Download ${item.altMsg}`, children: jsxRuntime.jsx("svg", { className: "h-6 w-6", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" }) }) })] }) }, item.id))) }) }), jsxRuntime.jsx("div", { className: "hidden sm:grid sm:grid-cols-2 lg:grid-cols-3 gap-6", children: data.items.map((item, index) => (jsxRuntime.jsxs("div", { className: "group relative overflow-hidden rounded-xl", "data-gallery-item": item.id, "data-gallery-index": index, children: [jsxRuntime.jsx(Image, { src: item.url, alt: item.altMsg, width: 600, height: 600, className: "w-full h-80 object-cover transition duration-300 group-hover:scale-105", "data-gallery-image": item.id }), jsxRuntime.jsx("div", { className: "absolute inset-0 flex items-end justify-end p-4 opacity-0 group-hover:opacity-100 transition duration-300", children: jsxRuntime.jsx("button", { className: "p-2 rounded-full bg-black/50 hover:bg-black/70 text-white/80 hover:text-white transition-all duration-300", "data-gallery-download": item.id, "aria-label": `Download ${item.altMsg}`, children: jsxRuntime.jsx("svg", { className: "h-5 w-5 text-white", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" }) }) }) })] }, item.id))) }), button && (jsxRuntime.jsx("div", { className: "text-center mt-12", children: button })), jsxRuntime.jsx(galleryInteractive.GalleryInteractive, { data: data })] }));
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
exports.Gallery = Gallery;
|
package/dist/main/gallery.mjs
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { __awaiter } from '../node_modules/.pnpm/@rollup_plugin-typescript@12.1.4_rollup@4.46.2_tslib@2.8.1_typescript@5.9.3/node_modules/tslib/tslib.es6.mjs';
|
|
2
|
-
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
3
|
-
import { getTranslations } from 'next-intl/server';
|
|
4
|
-
import { cn } from '@windrun-huaiin/lib/utils';
|
|
5
|
-
import Image from 'next/image';
|
|
6
|
-
import 'react';
|
|
7
|
-
import '@windrun-huaiin/base-ui/components/server';
|
|
8
|
-
import './nprogress-bar.mjs';
|
|
9
|
-
import '@windrun-huaiin/base-ui/ui';
|
|
10
|
-
import './rich-text-expert.mjs';
|
|
11
|
-
import 'next/navigation';
|
|
12
|
-
import { GalleryInteractive } from './gallery-interactive.mjs';
|
|
13
|
-
import '@clerk/nextjs';
|
|
14
|
-
import './money-price/money-price-types.mjs';
|
|
15
|
-
import 'next/link';
|
|
16
|
-
import { Swiper, SwiperSlide } from '../node_modules/.pnpm/swiper@12.0.3/node_modules/swiper/swiper-react.mjs';
|
|
17
|
-
import Pagination from '../node_modules/.pnpm/swiper@12.0.3/node_modules/swiper/modules/pagination.mjs';
|
|
18
|
-
import { responsiveSection } from './section-layout.mjs';
|
|
19
|
-
|
|
20
|
-
function Gallery(_a) {
|
|
21
|
-
return __awaiter(this, arguments, void 0, function* ({ locale, sectionClassName, button }) {
|
|
22
|
-
const t = yield getTranslations({ locale, namespace: 'gallery' });
|
|
23
|
-
const galleryItems = t.raw('prompts');
|
|
24
|
-
const data = {
|
|
25
|
-
titleL: t('titleL'),
|
|
26
|
-
eyesOn: t('eyesOn'),
|
|
27
|
-
titleR: t('titleR'),
|
|
28
|
-
description: t('description'),
|
|
29
|
-
items: galleryItems.map((item, index) => ({
|
|
30
|
-
id: `gallery-item-${index}`,
|
|
31
|
-
url: item.url,
|
|
32
|
-
altMsg: item.altMsg
|
|
33
|
-
})),
|
|
34
|
-
defaultImgUrl: t.raw('defaultImgUrl'),
|
|
35
|
-
downloadPrefix: t('downloadPrefix')
|
|
36
|
-
};
|
|
37
|
-
return (jsxs("section", { id: "gallery", className: cn(responsiveSection, sectionClassName), children: [jsxs("h2", { className: "text-3xl md:text-4xl font-bold text-center mb-6", children: [data.titleL, " ", jsx("span", { className: "text-purple-500", children: data.eyesOn }), " ", data.titleR] }), jsx("p", { className: "text-center max-w-2xl mx-auto mb-16", children: data.description }), jsx("div", { className: "block sm:hidden", children: jsx(Swiper, { modules: [Pagination], pagination: { clickable: true }, spaceBetween: 20, slidesPerView: 1, loop: true, className: "rounded-xl overflow-hidden", children: data.items.map((item, index) => (jsx(SwiperSlide, { children: jsxs("div", { className: "relative aspect-square bg-gray-100", children: [jsx(Image, { src: item.url, alt: item.altMsg, fill: true, className: "object-cover", "data-gallery-image": item.id }), jsx("button", { className: "absolute bottom-4 right-4 p-3 rounded-full bg-black/60 hover:bg-black/80 text-white transition-all z-10", "data-gallery-download": item.id, "aria-label": `Download ${item.altMsg}`, children: jsx("svg", { className: "h-6 w-6", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" }) }) })] }) }, item.id))) }) }), jsx("div", { className: "hidden sm:grid sm:grid-cols-2 lg:grid-cols-3 gap-6", children: data.items.map((item, index) => (jsxs("div", { className: "group relative overflow-hidden rounded-xl", "data-gallery-item": item.id, "data-gallery-index": index, children: [jsx(Image, { src: item.url, alt: item.altMsg, width: 600, height: 600, className: "w-full h-80 object-cover transition duration-300 group-hover:scale-105", "data-gallery-image": item.id }), jsx("div", { className: "absolute inset-0 flex items-end justify-end p-4 opacity-0 group-hover:opacity-100 transition duration-300", children: jsx("button", { className: "p-2 rounded-full bg-black/50 hover:bg-black/70 text-white/80 hover:text-white transition-all duration-300", "data-gallery-download": item.id, "aria-label": `Download ${item.altMsg}`, children: jsx("svg", { className: "h-5 w-5 text-white", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" }) }) }) })] }, item.id))) }), button && (jsx("div", { className: "text-center mt-12", children: button })), jsx(GalleryInteractive, { data: data })] }));
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export { Gallery };
|