photosuite 0.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/LICENSE +674 -0
- package/README.md +244 -0
- package/README.zh-CN.md +245 -0
- package/dist/Wild-squirrel-feeding-interaction-with-hand-in-natural-forest.png +0 -0
- package/dist/demo.d.ts +0 -0
- package/dist/dom-CDvVCbvk.js +36 -0
- package/dist/dom-DMZsb49p.cjs +1 -0
- package/dist/exif-DYpA7_Ip.cjs +1 -0
- package/dist/exif-Dr_aoh2F.js +7 -0
- package/dist/glightbox-Cnkb5Vpt.js +44 -0
- package/dist/glightbox-D14wFv8j.cjs +1 -0
- package/dist/imageAlts-BAYP9b5j.js +7 -0
- package/dist/imageAlts-CAX8Uksx.cjs +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/integration.d.ts +18 -0
- package/dist/modules/dom.d.ts +40 -0
- package/dist/modules/exif.d.ts +12 -0
- package/dist/modules/glightbox.d.ts +9 -0
- package/dist/modules/imageAlts.d.ts +12 -0
- package/dist/photosuite.cjs.js +1 -0
- package/dist/photosuite.css +2 -0
- package/dist/photosuite.es.js +21 -0
- package/dist/photosuite.integration.cjs +7 -0
- package/dist/photosuite.integration.js +173 -0
- package/dist/rehype/exiftoolVendored.d.ts +22 -0
- package/dist/remark/imageUrl.d.ts +17 -0
- package/dist/types.d.ts +134 -0
- package/dist/vite.svg +1 -0
- package/package.json +76 -0
package/README.md
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+

|
|
2
|
+
|
|
3
|
+
# Photosuite
|
|
4
|
+
|
|
5
|
+
[Official Website](https://photosuite.lhasa.icu) • [Latest Release](https://github.com/achuanya/photosuite/releases) • [Changelog](https://github.com/achuanya/photosuite/main/Changelog.md) • [简体中文](./README.zh-CN.md)
|
|
6
|
+
|
|
7
|
+
Photosuite is a simple yet feature-rich image integration tailored for independent blogs. It modularly integrates lightbox, EXIF data, path resolution, and more into a single, zero-config package. Out of the box, no tedious configuration required—give your blog images a fresh look with just one line of code!
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
* **Lightbox**: Customized and integrated GLightbox for a more minimalist and practical experience.
|
|
12
|
+
* **EXIF**: Integrated `exiftool-vendored.js` for fast execution and broad coverage.
|
|
13
|
+
* **Path Resolution**: Simply insert the filename, and it automatically resolves the absolute path.
|
|
14
|
+
* **Captions**: Automatically extracts the image's `alt` attribute to display as a caption.
|
|
15
|
+
* **Performance**: Purely static, modular features, loaded on demand.
|
|
16
|
+
* **Zero-Config Start**: Default settings satisfy most needs, while offering rich options for deep customization.
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pnpm add photosuite
|
|
22
|
+
# or
|
|
23
|
+
npm install photosuite
|
|
24
|
+
# or
|
|
25
|
+
yarn add photosuite
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Quick Start
|
|
29
|
+
|
|
30
|
+
Integrating Photosuite with Astro is very simple, just add the following configuration to `astro.config.js`:
|
|
31
|
+
|
|
32
|
+
```javascript
|
|
33
|
+
import { defineConfig } from 'astro/config';
|
|
34
|
+
import photosuite from 'photosuite';
|
|
35
|
+
import "photosuite/dist/photosuite.css";
|
|
36
|
+
|
|
37
|
+
export default defineConfig({
|
|
38
|
+
integrations: [
|
|
39
|
+
photosuite({
|
|
40
|
+
// [Required] Specify the CSS selector for the scope
|
|
41
|
+
// Recommended: Your content container to avoid affecting other parts of the site. Supports multiple selectors separated by commas.
|
|
42
|
+
scope: '#main',
|
|
43
|
+
})
|
|
44
|
+
]
|
|
45
|
+
});
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Once configured, Photosuite will automatically process all images in your Markdown/MDX files.
|
|
49
|
+
|
|
50
|
+
## Features & Configuration
|
|
51
|
+
|
|
52
|
+
### 1. Path Resolution
|
|
53
|
+
|
|
54
|
+
Managing image paths in blog posts can be tedious. Photosuite offers flexible resolution strategies that you can configure according to your needs.
|
|
55
|
+
|
|
56
|
+
**Scenario A: All images in a single domain/directory**
|
|
57
|
+
|
|
58
|
+
```javascript
|
|
59
|
+
photosuite({
|
|
60
|
+
scope: '#main',
|
|
61
|
+
imageBase: 'https://cdn.example.com/images/',
|
|
62
|
+
})
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**Markdown Usage:**
|
|
66
|
+
```markdown
|
|
67
|
+

|
|
68
|
+
<!-- Resolves to: https://cdn.example.com/images/photo.jpg -->
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**Scenario B: Separate image directory per post (Default)**
|
|
72
|
+
|
|
73
|
+
You can specify the directory name in the Frontmatter:
|
|
74
|
+
|
|
75
|
+
```yaml
|
|
76
|
+
---
|
|
77
|
+
title: My First GitHub PR
|
|
78
|
+
imageDir: "2025-11-26-my-first-github-pr"
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+

|
|
82
|
+
<!-- Resolves to: https://cdn.example.com/images/2025-11-26-my-first-github-pr/photo.jpg -->
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**Scenario C: Use filename as directory**
|
|
86
|
+
|
|
87
|
+
```javascript
|
|
88
|
+
photosuite({
|
|
89
|
+
scope: '#main',
|
|
90
|
+
imageBase: 'https://cdn.example.com/',
|
|
91
|
+
fileDir: true, // Enable this option
|
|
92
|
+
})
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
If your post filename is `2025-11-26-my-first-github-pr.md`, the image path automatically resolves to:
|
|
96
|
+
|
|
97
|
+
`https://cdn.example.com/images/2025-11-26-my-first-github-pr/photo.jpg`
|
|
98
|
+
|
|
99
|
+
### 2. EXIF Data Display
|
|
100
|
+
|
|
101
|
+
Photosuite uses `exiftool-vendored.js` to extract information at build time.
|
|
102
|
+
|
|
103
|
+
**Default Configuration:**
|
|
104
|
+
Default display: Camera Model, Lens Model, Focal Length, Aperture, Shutter Speed, ISO, Date Original.
|
|
105
|
+
|
|
106
|
+
> NIKON Z 30 · NIKKOR Z DX 16-50mm f/3.5-6.3 VR · 20.5 mm · ƒ/3.8 · 1/15 · ISO 1000 · 2025/12/9
|
|
107
|
+
|
|
108
|
+
**Custom Configuration:**
|
|
109
|
+
|
|
110
|
+
```javascript
|
|
111
|
+
photosuite({
|
|
112
|
+
// ...
|
|
113
|
+
exif: {
|
|
114
|
+
enabled: true,
|
|
115
|
+
// Custom fields: Focal Length, Aperture, Shutter Speed, ISO
|
|
116
|
+
fields: ['FocalLength', 'FNumber', 'ExposureTime', 'ISO'],
|
|
117
|
+
// Custom separator
|
|
118
|
+
separator: ' · '
|
|
119
|
+
}
|
|
120
|
+
})
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### 3. Lightbox & Captions
|
|
124
|
+
|
|
125
|
+
GLightbox has been customized to differ slightly from the official version.
|
|
126
|
+
|
|
127
|
+
Supports native configuration, refer to: [GLightbox](https://github.com/achuanya/glightbox)
|
|
128
|
+
|
|
129
|
+
```javascript
|
|
130
|
+
photosuite({
|
|
131
|
+
// ...
|
|
132
|
+
// Disable lightbox
|
|
133
|
+
glightbox: false,
|
|
134
|
+
|
|
135
|
+
// Disable captions
|
|
136
|
+
imageAlts: false,
|
|
137
|
+
|
|
138
|
+
// Pass native GLightbox options
|
|
139
|
+
glightboxOptions: {
|
|
140
|
+
loop: true,
|
|
141
|
+
zoomable: true,
|
|
142
|
+
}
|
|
143
|
+
})
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Complete Configuration Reference
|
|
147
|
+
|
|
148
|
+
### Parameter List
|
|
149
|
+
|
|
150
|
+
| Parameter | Type | Required | Default | Description |
|
|
151
|
+
| :--- | :--- | :---: | :--- | :--- |
|
|
152
|
+
| `scope` | `string` | ✅ | - | **Scope**. CSS selector, only processes images within this container. Supports multiple selectors separated by commas. |
|
|
153
|
+
| `selector` | `string` | ❌ | `"a.glightbox"` | **Image Selector**. Specifies which images need lightbox effect. |
|
|
154
|
+
| `imageBase` | `string` | ❌ | - | **Base Image URL**. Prefix used for splicing relative paths. |
|
|
155
|
+
| `imageDir` | `string` | ❌ | `"imageDir"` | **Directory Field Name**. Field name in Markdown Frontmatter to specify image subdirectory. |
|
|
156
|
+
| `fileDir` | `boolean` | ❌ | `false` | **Filename Archiving**. Whether to automatically use Markdown filename as image subdirectory. |
|
|
157
|
+
| `glightbox` | `boolean` | ❌ | `true` | **Enable Lightbox**. Whether to load GLightbox module. |
|
|
158
|
+
| `imageAlts` | `boolean` | ❌ | `true` | **Enable Captions**. Whether to display `alt` attribute as image caption. |
|
|
159
|
+
| `exif` | `boolean` \| `object` | ❌ | `true` | **Enable EXIF**. `false` to disable, `true` for default config, or pass object to customize via fields:[]. |
|
|
160
|
+
| `glightboxOptions` | `object` | ❌ | - | **Native Lightbox Config**. Configuration items passed through to GLightbox. |
|
|
161
|
+
|
|
162
|
+
### Full Configuration Code Example
|
|
163
|
+
|
|
164
|
+
```javascript
|
|
165
|
+
import photosuite from 'photosuite';
|
|
166
|
+
import "photosuite/dist/photosuite.css";
|
|
167
|
+
|
|
168
|
+
photosuite({
|
|
169
|
+
// ----------------
|
|
170
|
+
// Required
|
|
171
|
+
// ----------------
|
|
172
|
+
scope: '#main', // Your content container class name
|
|
173
|
+
|
|
174
|
+
// ----------------
|
|
175
|
+
// Optional (Values below are defaults)
|
|
176
|
+
// ----------------
|
|
177
|
+
|
|
178
|
+
// Basic Settings
|
|
179
|
+
selector: 'a.glightbox',
|
|
180
|
+
|
|
181
|
+
// Path Resolution
|
|
182
|
+
imageBase: '',
|
|
183
|
+
imageDir: 'imageDir',
|
|
184
|
+
fileDir: false,
|
|
185
|
+
|
|
186
|
+
// Feature Toggles
|
|
187
|
+
glightbox: true,
|
|
188
|
+
imageAlts: true,
|
|
189
|
+
|
|
190
|
+
// EXIF Detailed Configuration
|
|
191
|
+
exif: {
|
|
192
|
+
enabled: true,
|
|
193
|
+
fields: [
|
|
194
|
+
'Model', // Camera Model
|
|
195
|
+
'LensModel', // Lens Model
|
|
196
|
+
'FocalLength', // Focal Length
|
|
197
|
+
'FNumber', // Aperture
|
|
198
|
+
'ExposureTime', // Shutter Speed
|
|
199
|
+
'ISO', // ISO
|
|
200
|
+
'DateTimeOriginal' // Date Original
|
|
201
|
+
],
|
|
202
|
+
separator: ' · ' // Separator
|
|
203
|
+
},
|
|
204
|
+
|
|
205
|
+
// Native GLightbox Configuration
|
|
206
|
+
glightboxOptions: {
|
|
207
|
+
loop: true,
|
|
208
|
+
touchNavigation: true,
|
|
209
|
+
closeOnOutsideClick: true
|
|
210
|
+
}
|
|
211
|
+
})
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## FAQ
|
|
215
|
+
|
|
216
|
+
**Q: Why isn't EXIF data showing?**
|
|
217
|
+
A: Please check the following:
|
|
218
|
+
1. Does the image contain EXIF data? (Some compression tools strip EXIF)
|
|
219
|
+
2. EXIF data is only displayed when at least the exposure triangle (Focal Length, Aperture, Shutter Speed) is present.
|
|
220
|
+
|
|
221
|
+
**Q: I only want to use Photosuite on certain images, what should I do?**
|
|
222
|
+
A: You can precisely control the scope via CSS selectors (comma-separated for multiple selectors). For example, only take effect inside elements with ID `#main`:
|
|
223
|
+
|
|
224
|
+
```javascript
|
|
225
|
+
photosuite({
|
|
226
|
+
scope: '#main',
|
|
227
|
+
// ... other configurations
|
|
228
|
+
})
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## Contributors
|
|
232
|
+
|
|
233
|
+
One line of code, one plugin, for independent blogs, it is insignificant, like dust.
|
|
234
|
+
|
|
235
|
+
But we insist on taking root in this soil, letting thought be free, and letting the soul rest!
|
|
236
|
+
|
|
237
|
+
[](https://github.com/achuanya/photosuite/graphs/contributors)
|
|
238
|
+
|
|
239
|
+
## Supporters
|
|
240
|
+
[](https://github.com/achuanya/photosuite/stargazers)
|
|
241
|
+
|
|
242
|
+
## License
|
|
243
|
+
|
|
244
|
+
[GPL-3.0](./LICENSE)
|
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+

|
|
2
|
+
|
|
3
|
+
# Photosuite
|
|
4
|
+
|
|
5
|
+
[官方网站](https://photosuite.lhasa.icu) • [最新版本](https://github.com/achuanya/photosuite/releases) • [更新日志](https://github.com/achuanya/photosuite/main/Changelog.md) • [English](./README.md)
|
|
6
|
+
|
|
7
|
+
Photosuite 是一款简单易用但功能丰富的图像插件,它将灯箱、EXIF、路径补全等功能,模块化整合在一个零配置的插件中。开箱即用,无需繁琐的配置,一行代码即可让您的图片焕然一新!
|
|
8
|
+
|
|
9
|
+
## 特性
|
|
10
|
+
|
|
11
|
+
* **灯箱**:定制并集成 GLightbox 灯箱,更简约、更实用
|
|
12
|
+
* **EXIF**:集成 exiftool-vendored.js 执行快、覆盖广
|
|
13
|
+
* **路径**:只需要插入文件名,自动补全绝对路径
|
|
14
|
+
* **标题**:自动获取图片alt进行标题展示
|
|
15
|
+
* **性能**:纯静态,功能模块化,按需加载
|
|
16
|
+
* **零配置启动**:默认配置即可满足绝大多数需求,同时也提供丰富的选项供深度定制
|
|
17
|
+
|
|
18
|
+
## 安装
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pnpm add photosuite
|
|
22
|
+
# 或
|
|
23
|
+
npm install photosuite
|
|
24
|
+
# 或
|
|
25
|
+
yarn add photosuite
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## 快速开始
|
|
29
|
+
|
|
30
|
+
Astro 集成 Photosuite 非常简单,只需要在 `astro.config.js` 中添加以下配置:
|
|
31
|
+
|
|
32
|
+
```javascript
|
|
33
|
+
import { defineConfig } from 'astro/config';
|
|
34
|
+
import photosuite from 'photosuite';
|
|
35
|
+
import "photosuite/dist/photosuite.css";
|
|
36
|
+
|
|
37
|
+
export default defineConfig({
|
|
38
|
+
integrations: [
|
|
39
|
+
photosuite({
|
|
40
|
+
// [必填] 指定生效范围的 CSS 选择器
|
|
41
|
+
// 建议指定为您的文章容器,避免影响网站其他部分。支持多个选择器,用逗号分隔
|
|
42
|
+
scope: '#main',
|
|
43
|
+
})
|
|
44
|
+
]
|
|
45
|
+
});
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
配置完成后,Photosuite 会自动处理您 Markdown/MDX 中的所有图片。
|
|
49
|
+
|
|
50
|
+
## 功能详解与配置
|
|
51
|
+
|
|
52
|
+
### 1. 路径解析
|
|
53
|
+
|
|
54
|
+
在写博客时,图片路径往往很麻烦。Photosuite 提供了灵活的路径解析策略,您可以根据实际情况进行配置
|
|
55
|
+
|
|
56
|
+
**场景 A:所有图片都在一个域名下**
|
|
57
|
+
|
|
58
|
+
```javascript
|
|
59
|
+
photosuite({
|
|
60
|
+
scope: '#main',
|
|
61
|
+
imageBase: 'https://cdn.example.com/images/',
|
|
62
|
+
})
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**Markdown 写法:**
|
|
66
|
+
```markdown
|
|
67
|
+

|
|
68
|
+
<!-- 最终解析为: https://cdn.example.com/images/photo.jpg -->
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**场景 B:每篇文章有独立的图片目录(默认)**
|
|
72
|
+
|
|
73
|
+
您可以在 Frontmatter 中指定目录名:
|
|
74
|
+
|
|
75
|
+
```yaml
|
|
76
|
+
---
|
|
77
|
+
title: 我的第一次 GitHub PR
|
|
78
|
+
imageDir: "2025-11-26-my-first-github-pr"
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+

|
|
82
|
+
<!-- 最终解析为: https://cdn.example.com/images/2025-11-26-my-first-github-pr/photo.jpg -->
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**场景 C:以文件名为目录**
|
|
86
|
+
|
|
87
|
+
```javascript
|
|
88
|
+
photosuite({
|
|
89
|
+
scope: '#main',
|
|
90
|
+
imageBase: 'https://cdn.example.com/',
|
|
91
|
+
fileDir: true, // 开启此选项
|
|
92
|
+
})
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
如果您的文章文件名是 `2025-11-26-my-first-github-pr.md`,图片路径会自动解析为:
|
|
96
|
+
|
|
97
|
+
`https://cdn.example.com/images/2025-11-26-my-first-github-pr/photo.jpg`
|
|
98
|
+
|
|
99
|
+
### 2. EXIF 信息展示
|
|
100
|
+
|
|
101
|
+
Photosuite 使用 `exiftool-vendored.js` 在构建时提取信息。
|
|
102
|
+
|
|
103
|
+
**默认配置:**
|
|
104
|
+
默认显示:相机型号、镜头型号、焦距、光圈、快门速度、ISO、拍摄时间。
|
|
105
|
+
|
|
106
|
+
> NIKON Z 30 · NIKKOR Z DX 16-50mm f/3.5-6.3 VR · 20.5 mm · ƒ/3.8 · 1/15 · ISO 1000 · 2025/12/9
|
|
107
|
+
|
|
108
|
+
**自定义配置:**
|
|
109
|
+
|
|
110
|
+
```javascript
|
|
111
|
+
photosuite({
|
|
112
|
+
// ...
|
|
113
|
+
exif: {
|
|
114
|
+
enabled: true,
|
|
115
|
+
// 自定义显示字段:焦距、光圈、快门速度、ISO
|
|
116
|
+
fields: ['FocalLength', 'FNumber', 'ExposureTime', 'ISO'],
|
|
117
|
+
// 自定义分隔符
|
|
118
|
+
separator: ' · '
|
|
119
|
+
}
|
|
120
|
+
})
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### 3. 灯箱与标题
|
|
124
|
+
|
|
125
|
+
GLightbox 经过我定制后,与官方版本有些许差异
|
|
126
|
+
|
|
127
|
+
支持原生配置,可参考:[GLightbox](https://github.com/achuanya/glightbox)
|
|
128
|
+
|
|
129
|
+
```javascript
|
|
130
|
+
photosuite({
|
|
131
|
+
// ...
|
|
132
|
+
// 关闭灯箱功能
|
|
133
|
+
glightbox: false,
|
|
134
|
+
|
|
135
|
+
// 关闭图片标题
|
|
136
|
+
imageAlts: false,
|
|
137
|
+
|
|
138
|
+
// GLightbox 原生配置传递
|
|
139
|
+
glightboxOptions: {
|
|
140
|
+
loop: true,
|
|
141
|
+
zoomable: true,
|
|
142
|
+
}
|
|
143
|
+
})
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## 完整配置参考
|
|
147
|
+
|
|
148
|
+
### 参数列表
|
|
149
|
+
|
|
150
|
+
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|
|
151
|
+
| :--- | :--- | :---: | :--- | :--- |
|
|
152
|
+
| `scope` | `string` | ✅ | - | **生效范围**。CSS 选择器,仅处理该容器内的图片,可包含多个选择器,用逗号分隔 |
|
|
153
|
+
| `selector` | `string` | ❌ | `"a.glightbox"` | **图片选择器**。指定哪些图片需要启用灯箱效果 |
|
|
154
|
+
| `imageBase` | `string` | ❌ | - | **图片基础 URL**。用于拼接相对路径的前缀 |
|
|
155
|
+
| `imageDir` | `string` | ❌ | `"imageDir"` | **目录字段名**。在 Markdown Frontmatter 中指定图片目录的字段名称 |
|
|
156
|
+
| `fileDir` | `boolean` | ❌ | `false` | **文件名归档**。是否自动使用 Markdown 文件名作为图片子目录 |
|
|
157
|
+
| `glightbox` | `boolean` | ❌ | `true` | **启用灯箱**。是否加载 GLightbox 模块 |
|
|
158
|
+
| `imageAlts` | `boolean` | ❌ | `true` | **启用标题**。是否将 `alt` 属性显示为图片标题 |
|
|
159
|
+
| `exif` | `boolean` \| `object` | ❌ | `true` | **启用 EXIF**。可通过 fields:[] 配置显示选项 |
|
|
160
|
+
| `glightboxOptions` | `object` | ❌ | - | **灯箱原生配置**。透传给 GLightbox 的配置项 |
|
|
161
|
+
|
|
162
|
+
### 全部配置代码示例
|
|
163
|
+
|
|
164
|
+
```javascript
|
|
165
|
+
import photosuite from 'photosuite';
|
|
166
|
+
import "photosuite/dist/photosuite.css";
|
|
167
|
+
|
|
168
|
+
photosuite({
|
|
169
|
+
// ----------------
|
|
170
|
+
// 必填项
|
|
171
|
+
// ----------------
|
|
172
|
+
scope: '#main', // 您的文章容器类名
|
|
173
|
+
|
|
174
|
+
// ----------------
|
|
175
|
+
// 选填项 (以下均为默认值)
|
|
176
|
+
// ----------------
|
|
177
|
+
|
|
178
|
+
// 基础设置
|
|
179
|
+
selector: 'a.glightbox',
|
|
180
|
+
|
|
181
|
+
// 路径解析
|
|
182
|
+
imageBase: '',
|
|
183
|
+
imageDir: 'imageDir',
|
|
184
|
+
fileDir: false,
|
|
185
|
+
|
|
186
|
+
// 功能开关
|
|
187
|
+
glightbox: true,
|
|
188
|
+
imageAlts: true,
|
|
189
|
+
|
|
190
|
+
// EXIF 详细配置
|
|
191
|
+
exif: {
|
|
192
|
+
enabled: true,
|
|
193
|
+
fields: [
|
|
194
|
+
'Model', // 相机型号
|
|
195
|
+
'LensModel', // 镜头型号
|
|
196
|
+
'FocalLength', // 焦距
|
|
197
|
+
'FNumber', // 光圈
|
|
198
|
+
'ExposureTime', // 快门速度
|
|
199
|
+
'ISO', // 感光度
|
|
200
|
+
'DateTimeOriginal' // 拍摄时间
|
|
201
|
+
],
|
|
202
|
+
separator: ' · ' // 分隔符
|
|
203
|
+
},
|
|
204
|
+
|
|
205
|
+
// GLightbox 原生配置
|
|
206
|
+
glightboxOptions: {
|
|
207
|
+
loop: true,
|
|
208
|
+
touchNavigation: true,
|
|
209
|
+
closeOnOutsideClick: true
|
|
210
|
+
}
|
|
211
|
+
})
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## 常见问题
|
|
215
|
+
|
|
216
|
+
**1.为什么 EXIF 信息没有显示?**
|
|
217
|
+
A: 请检查以下几点:
|
|
218
|
+
|
|
219
|
+
1. 图片是否包含 EXIF 信息(某些压缩工具会去除 EXIF)
|
|
220
|
+
2. EXIF 信息至少有曝光三要素(焦距、光圈、快门速度)时,才会显示
|
|
221
|
+
|
|
222
|
+
**2.我想只在某些图片上使用 Photosuite,怎么办?**
|
|
223
|
+
A: 您可以通过 CSS 选择器精确控制范围(多个选择器用逗号分隔)例如,只在类名为 `'#main` 的元素内部生效:
|
|
224
|
+
|
|
225
|
+
```javascript
|
|
226
|
+
photosuite({
|
|
227
|
+
scope: '#main',
|
|
228
|
+
// ... 其他配置
|
|
229
|
+
})
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
## 贡献者们
|
|
233
|
+
|
|
234
|
+
一行代码,一个插件,对于独立博客而言,微不足道,如同尘埃。
|
|
235
|
+
|
|
236
|
+
但我们偏要在这片土壤中扎根,让思想自由,让灵魂安放!
|
|
237
|
+
|
|
238
|
+
[](https://github.com/achuanya/photosuite/graphs/contributors)
|
|
239
|
+
|
|
240
|
+
## 支持者们
|
|
241
|
+
[](https://github.com/achuanya/photosuite/stargazers)
|
|
242
|
+
|
|
243
|
+
## 开源许可协议
|
|
244
|
+
|
|
245
|
+
[GPL-3.0](./LICENSE)
|
package/dist/demo.d.ts
ADDED
|
File without changes
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
function ensurePhotosuiteContainer(e) {
|
|
2
|
+
let t = e.parentElement;
|
|
3
|
+
if (!t) return e;
|
|
4
|
+
let n = e;
|
|
5
|
+
e.tagName.toLowerCase() === "img" && t && t.tagName.toLowerCase() === "a" && t.classList.contains("glightbox") && (n = t);
|
|
6
|
+
let r = n.parentElement;
|
|
7
|
+
if (r && r.classList.contains("photosuite-item")) return r;
|
|
8
|
+
let i = document.createElement("div");
|
|
9
|
+
i.className = "photosuite-item";
|
|
10
|
+
let a = n.parentElement;
|
|
11
|
+
return a ? (a.replaceChild(i, n), i.appendChild(n), i) : i;
|
|
12
|
+
}
|
|
13
|
+
function processMedia(t, n, r) {
|
|
14
|
+
let i = /* @__PURE__ */ new Set(), a = (t) => {
|
|
15
|
+
let n = ensurePhotosuiteContainer(t);
|
|
16
|
+
i.has(n) || n.querySelector("img") && (r(n), i.add(n));
|
|
17
|
+
};
|
|
18
|
+
document.querySelectorAll(t).forEach((e) => {
|
|
19
|
+
e.querySelectorAll(n).forEach(a), e.querySelectorAll("img").forEach(a);
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
function ensureCaption(e) {
|
|
23
|
+
if (e.querySelector(".photosuite-caption")) return;
|
|
24
|
+
let t = e.querySelector("img");
|
|
25
|
+
if (!t) return;
|
|
26
|
+
let n = String(t.getAttribute("alt") || "").trim();
|
|
27
|
+
if (!n) return;
|
|
28
|
+
let r = document.createElement("div");
|
|
29
|
+
r.className = "photosuite-caption", r.textContent = n, e.appendChild(r);
|
|
30
|
+
}
|
|
31
|
+
function ensureExif(e) {
|
|
32
|
+
if (e.querySelector(".photosuite-exif")) return;
|
|
33
|
+
let t = document.createElement("div");
|
|
34
|
+
t.className = "photosuite-exif", e.appendChild(t);
|
|
35
|
+
}
|
|
36
|
+
export { ensureExif as n, processMedia as r, ensureCaption as t };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function e(e){let t=e.parentElement;if(!t)return e;let n=e;e.tagName.toLowerCase()===`img`&&t&&t.tagName.toLowerCase()===`a`&&t.classList.contains(`glightbox`)&&(n=t);let r=n.parentElement;if(r&&r.classList.contains(`photosuite-item`))return r;let i=document.createElement(`div`);i.className=`photosuite-item`;let a=n.parentElement;return a?(a.replaceChild(i,n),i.appendChild(n),i):i}function t(t,n,r){let i=new Set,a=t=>{let n=e(t);i.has(n)||n.querySelector(`img`)&&(r(n),i.add(n))};document.querySelectorAll(t).forEach(e=>{e.querySelectorAll(n).forEach(a),e.querySelectorAll(`img`).forEach(a)})}function n(e){if(e.querySelector(`.photosuite-caption`))return;let t=e.querySelector(`img`);if(!t)return;let n=String(t.getAttribute(`alt`)||``).trim();if(!n)return;let r=document.createElement(`div`);r.className=`photosuite-caption`,r.textContent=n,e.appendChild(r)}function r(e){if(e.querySelector(`.photosuite-exif`))return;let t=document.createElement(`div`);t.className=`photosuite-exif`,e.appendChild(t)}Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return r}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return t}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return n}});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e=require(`./dom-DMZsb49p.cjs`);async function t(t,n){await Promise.resolve().then(()=>require(`./exif-DwHkZ3YD.cjs`)),e.r(t,n,t=>{e.n(t)})}exports.enableExif=t;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
function wrap(e, t) {
|
|
2
|
+
let n = e.currentSrc || e.src || "";
|
|
3
|
+
if (!n) return;
|
|
4
|
+
let r = String(e.getAttribute("alt") || "").trim(), i = document.createElement("a");
|
|
5
|
+
i.href = n, i.className = "glightbox", i.dataset.gallery = t, r && (i.dataset.title = r), e.parentElement.replaceChild(i, e), i.appendChild(e);
|
|
6
|
+
}
|
|
7
|
+
function sync(e, t) {
|
|
8
|
+
let n = e.querySelector("img");
|
|
9
|
+
if (!n) return;
|
|
10
|
+
let r = n.currentSrc || n.src;
|
|
11
|
+
r && e.getAttribute("href") !== r && e.setAttribute("href", r);
|
|
12
|
+
let i = n.getAttribute("alt");
|
|
13
|
+
i && !e.dataset.title && (e.dataset.title = i), e.dataset.gallery || (e.dataset.gallery = t);
|
|
14
|
+
}
|
|
15
|
+
function loadCss(e) {
|
|
16
|
+
if (!e || document.querySelector(`link[href="${e}"]`)) return;
|
|
17
|
+
let t = document.createElement("link");
|
|
18
|
+
t.rel = "stylesheet", t.href = e, document.head.appendChild(t);
|
|
19
|
+
}
|
|
20
|
+
function loadJs(e) {
|
|
21
|
+
return new Promise((t) => {
|
|
22
|
+
if (!e || typeof window.GLightbox == "function") return t();
|
|
23
|
+
let n = document.createElement("script");
|
|
24
|
+
n.src = e, n.onload = () => t(), document.head.appendChild(n);
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
async function initGlightboxModule(i) {
|
|
28
|
+
let a = i.selector, o = i.scope, s = i.gallery, c = i.cssUrl || "https://cos.lhasa.icu/dist/glightbox/glightbox.min.css", l = i.jsUrl || "https://cos.lhasa.icu/dist/glightbox/glightbox.min.js", u = /* @__PURE__ */ new Set(), d = /* @__PURE__ */ new Set();
|
|
29
|
+
document.querySelectorAll(o).forEach((e) => {
|
|
30
|
+
e.querySelectorAll("img").forEach((e) => u.add(e)), e.querySelectorAll(a).forEach((e) => d.add(e));
|
|
31
|
+
}), u.forEach((t) => {
|
|
32
|
+
let n = t.parentElement, r = n && n.tagName.toLowerCase() === "a", i = r && n.classList.contains("glightbox");
|
|
33
|
+
(!r || !i) && wrap(t, s);
|
|
34
|
+
}), d.forEach((e) => sync(e, s)), loadCss(c), await loadJs(l), (() => {
|
|
35
|
+
let e = window.GLightbox;
|
|
36
|
+
if (typeof e == "function") {
|
|
37
|
+
let t = window.__glightboxInstance;
|
|
38
|
+
t && t.destroy && t.destroy();
|
|
39
|
+
let n = Object.assign({}, i.options || {}, { selector: a });
|
|
40
|
+
window.__glightboxInstance = e(n);
|
|
41
|
+
}
|
|
42
|
+
})();
|
|
43
|
+
}
|
|
44
|
+
export { initGlightboxModule };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function e(e,t){let n=e.currentSrc||e.src||``;if(!n)return;let r=String(e.getAttribute(`alt`)||``).trim(),i=document.createElement(`a`);i.href=n,i.className=`glightbox`,i.dataset.gallery=t,r&&(i.dataset.title=r),e.parentElement.replaceChild(i,e),i.appendChild(e)}function t(e,t){let n=e.querySelector(`img`);if(!n)return;let r=n.currentSrc||n.src;r&&e.getAttribute(`href`)!==r&&e.setAttribute(`href`,r);let i=n.getAttribute(`alt`);i&&!e.dataset.title&&(e.dataset.title=i),e.dataset.gallery||(e.dataset.gallery=t)}function n(e){if(!e||document.querySelector(`link[href="${e}"]`))return;let t=document.createElement(`link`);t.rel=`stylesheet`,t.href=e,document.head.appendChild(t)}function r(e){return new Promise(t=>{if(!e||typeof window.GLightbox==`function`)return t();let n=document.createElement(`script`);n.src=e,n.onload=()=>t(),document.head.appendChild(n)})}async function i(i){let a=i.selector,o=i.scope,s=i.gallery,c=i.cssUrl||`https://cos.lhasa.icu/dist/glightbox/glightbox.min.css`,l=i.jsUrl||`https://cos.lhasa.icu/dist/glightbox/glightbox.min.js`,u=new Set,d=new Set;document.querySelectorAll(o).forEach(e=>{e.querySelectorAll(`img`).forEach(e=>u.add(e)),e.querySelectorAll(a).forEach(e=>d.add(e))}),u.forEach(t=>{let n=t.parentElement,r=n&&n.tagName.toLowerCase()===`a`,i=r&&n.classList.contains(`glightbox`);(!r||!i)&&e(t,s)}),d.forEach(e=>t(e,s)),n(c),await r(l),(()=>{let e=window.GLightbox;if(typeof e==`function`){let t=window.__glightboxInstance;t&&t.destroy&&t.destroy();let n=Object.assign({},i.options||{},{selector:a});window.__glightboxInstance=e(n)}})()}exports.initGlightboxModule=i;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e=require(`./dom-DMZsb49p.cjs`);async function t(t,n){await Promise.resolve().then(()=>require(`./image-alts-D2zawu5U.cjs`)),e.r(t,n,t=>{e.t(t)})}exports.enableImageAlts=t;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { PhotosuiteOptions } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* 初始化 Photosuite
|
|
4
|
+
*
|
|
5
|
+
* 根据配置项动态加载并初始化各个功能模块(GLightbox, ImageAlts, Exif)
|
|
6
|
+
*
|
|
7
|
+
* @param opts - Photosuite 配置项
|
|
8
|
+
*/
|
|
9
|
+
export declare function photosuite(opts: PhotosuiteOptions): void;
|
|
10
|
+
export type { PhotosuiteOptions, ImageUrlOptions } from './types';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { PhotosuiteOptions } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Astro 集成默认导出
|
|
4
|
+
*
|
|
5
|
+
* 提供给 Astro 框架使用的集成配置。
|
|
6
|
+
*
|
|
7
|
+
* @param options - Photosuite 配置项
|
|
8
|
+
* @returns Astro 集成对象
|
|
9
|
+
*/
|
|
10
|
+
export default function astroPhotosuite(options: PhotosuiteOptions): {
|
|
11
|
+
name: string;
|
|
12
|
+
hooks: {
|
|
13
|
+
"astro:config:setup": ({ injectScript, updateConfig }: any) => void;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
export { imageUrl } from './remark/imageUrl';
|
|
17
|
+
export { exiftoolVendored } from './rehype/exiftoolVendored';
|
|
18
|
+
export type { PhotosuiteOptions, ImageUrlOptions } from './types';
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file dom.ts
|
|
3
|
+
* @description 提供 DOM 操作相关的辅助函数,用于处理图片容器、标题和 EXIF 元素的创建与管理
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* 确保元素被包裹在 photosuite-item 容器中
|
|
7
|
+
*
|
|
8
|
+
* 如果目标元素(通常是 img 或 a.glightbox)尚未被 photosuite-item 包裹
|
|
9
|
+
* 则创建一个新的 div.photosuite-item 并将目标元素移动到其中
|
|
10
|
+
*
|
|
11
|
+
* @param el - 需要检查或包裹的 DOM 元素
|
|
12
|
+
* @returns 包含该元素的 HTMLElement 容器 (.photosuite-item)
|
|
13
|
+
*/
|
|
14
|
+
export declare function ensurePhotosuiteContainer(el: Element): HTMLElement;
|
|
15
|
+
/**
|
|
16
|
+
* 处理媒体元素
|
|
17
|
+
*
|
|
18
|
+
* 遍历匹配选择器的元素以及所有 img 元素,确保它们拥有统一的容器结构
|
|
19
|
+
* 然后对每个容器执行回调函数
|
|
20
|
+
*
|
|
21
|
+
* @param selector - 用于选择图片或链接的选择器字符串
|
|
22
|
+
* @param callback - 对每个处理后的容器执行的回调函数
|
|
23
|
+
*/
|
|
24
|
+
export declare function processMedia(scope: string, selector: string, callback: (container: HTMLElement) => void): void;
|
|
25
|
+
/**
|
|
26
|
+
* 确保容器内存在标题元素
|
|
27
|
+
*
|
|
28
|
+
* 根据容器内图片的 alt 属性创建并插入标题元素
|
|
29
|
+
*
|
|
30
|
+
* @param container - 图片容器 (.photosuite-item)
|
|
31
|
+
*/
|
|
32
|
+
export declare function ensureCaption(container: HTMLElement): void;
|
|
33
|
+
/**
|
|
34
|
+
* 确保容器内存在 EXIF 显示条
|
|
35
|
+
*
|
|
36
|
+
* 创建一个用于显示 EXIF 信息的占位元素
|
|
37
|
+
*
|
|
38
|
+
* @param container - 图片容器 (.photosuite-item)
|
|
39
|
+
*/
|
|
40
|
+
export declare function ensureExif(container: HTMLElement): void;
|