Skip to content

Commit 4fe63b1

Browse files
committed
feat: new tag picture-caption
1 parent 8aa84d7 commit 4fe63b1

5 files changed

Lines changed: 142 additions & 0 deletions

File tree

_config.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,21 @@ mermaid:
552552
wavedrom:
553553
enable: false
554554

555+
# Picture Caption tag
556+
picture_caption:
557+
picture_border_radius:
558+
enable: false
559+
radius_size: 5px
560+
# Picture gap size between pictures. No strict validation for units; the `px` unit is also acceptable.
561+
picture_gap: 0.5em
562+
# Available caption position: top | bottom
563+
caption_position: bottom
564+
# Available caption alignment: left | center | right
565+
caption_alignment: center
566+
# Caption margin size between picture and caption. No strict validation for units; the `px` unit is also acceptable.
567+
caption_margin: 0.5em
568+
caption_font_size: 0.875em
569+
555570
# ---------------------------------------------------------------
556571
# Third Party Plugins & Services Settings
557572
# See: https://theme-next.js.org/docs/third-party-services/

scripts/tags/index.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@ const pdf = require('./pdf')(hexo);
4848

4949
hexo.extend.tag.register('pdf', pdf);
5050

51+
const pictureCaption = require('./picture-caption')(hexo);
52+
53+
hexo.extend.tag.register('picturecaption', pictureCaption);
54+
hexo.extend.tag.register('piccap', pictureCaption);
55+
hexo.extend.tag.register('pc', pictureCaption);
56+
5157
const postTabs = require('./tabs')(hexo);
5258

5359
hexo.extend.tag.register('tabs', postTabs, true);

scripts/tags/picture-caption.js

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/**
2+
* picture-caption.js | https://theme-next.js.org/docs/tag-plugins/picture-caption
3+
* Description: Insert an image with caption.
4+
* Usage:
5+
* {% picturecaption pictureUrl, captionText %}
6+
* {% picturecaption pictureUrl, pictureWidth, pictureHeight, captionText, captionUrl, captionIcon, captionPosition, captionAlignment %}
7+
*/
8+
9+
'use strict';
10+
11+
module.exports = ctx => function(args) {
12+
args = args.join(' ').split(',');
13+
14+
const pictureUrl = args[0].trim();
15+
if (!pictureUrl) {
16+
ctx.log.warn('Image URL can NOT be empty in picture-caption tag.');
17+
return '';
18+
}
19+
20+
// Default value.
21+
let pictureWidth = 'auto';
22+
let pictureHeight = 'auto';
23+
let captionText = '';
24+
let captionUrl = '';
25+
let captionIcon = '';
26+
const theme = ctx.theme.config;
27+
let captionPosition = theme.picture_caption.caption_position;
28+
let captionAlignment = theme.picture_caption.caption_alignment;
29+
30+
// Determine the invocation method based on the number of parameters.
31+
if (args.length === 2) {
32+
captionText = args[1].trim() || 'Picture';
33+
} else if (args.length >= 3) {
34+
// Take parameters from back to front.
35+
captionAlignment = ['left', 'center', 'right'].includes(args[args.length - 1].trim()) ? args.pop().trim() : 'center';
36+
captionPosition = ['top', 'bottom'].includes(args[args.length - 1].trim()) ? args.pop().trim() : 'bottom';
37+
captionIcon = args.pop().trim(); // This value can be null.
38+
captionUrl = args.pop().trim(); // This value can be null.
39+
// Take parameters from front to back.
40+
pictureWidth = args[1].trim() || 'auto';
41+
pictureHeight = args[2].trim() || 'auto';
42+
// Allow the captionText to contain English commas, and extract all characters starting from index 3 to the end.
43+
captionText = args.slice(3).join(',') || 'Picture';
44+
}
45+
46+
const style = `width: ${pictureWidth}; height: ${pictureHeight}; object-fit: contain;`;
47+
48+
const imgTag = `<img src="${pictureUrl}" alt="${captionText || 'Picture'}" style="${style}">`;
49+
50+
// Handle captionUrl and captionIcon, default value is null, 'None/none' or empty string is considered as no link.
51+
const hascaptionUrl = captionUrl && captionUrl.toLowerCase() !== 'none';
52+
const hascaptionIcon = captionIcon && captionIcon.toLowerCase() !== 'none';
53+
54+
let captionHtml = '';
55+
if (captionText) {
56+
let captionContent = '';
57+
if (hascaptionIcon) {
58+
if (!captionIcon.startsWith('fa')) { captionIcon = 'fa fa-' + captionIcon; }
59+
captionContent = `<i class="${captionIcon}"></i>${captionText}`;
60+
} else {
61+
captionContent = captionText;
62+
}
63+
if (hascaptionUrl) {
64+
captionContent = `<a href="${captionUrl}" target="_blank">${captionContent}</a>`;
65+
}
66+
captionHtml = `<div class="picture-caption-caption picture-caption-align-${captionAlignment}">${captionContent}</div>`;
67+
}
68+
69+
// Determine the order based on captionPosition.
70+
const content
71+
= captionPosition === 'bottom'
72+
? `${imgTag}${captionHtml}`
73+
: `${captionHtml}${imgTag}`;
74+
75+
return `<div class="picture-caption-container picture-caption-position-${captionPosition}" style="max-width: ${pictureWidth};">${content}</div>`;
76+
};

source/css/_common/scaffolding/tags/index.styl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@
66
@import 'wavedrom';
77
@import 'note';
88
@import 'pdf';
9+
@import 'picture-caption';
910
@import 'tabs';
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
.picture-caption-container {
2+
display: inline-flex;
3+
flex-direction: column;
4+
margin-bottom: 20px;
5+
vertical-align: bottom;
6+
}
7+
8+
.picture-caption-container + .picture-caption-container {
9+
margin-left: unquote(hexo-config('picture_caption.picture_gap'));
10+
}
11+
12+
.picture-caption-container img {
13+
margin: 0 !important;
14+
if(hexo-config('picture_caption.picture_border_radius.enable'))
15+
{
16+
border-radius: unquote(hexo-config('picture_caption.picture_border_radius.radius_size'));
17+
}
18+
}
19+
20+
.picture-caption-caption {
21+
margin: 0;
22+
line-height: 1;
23+
font-size: unquote(hexo-config('picture_caption.caption_font_size'));
24+
}
25+
26+
.picture-caption-align-left {
27+
text-align: left;
28+
}
29+
30+
.picture-caption-align-center {
31+
text-align: center;
32+
}
33+
34+
.picture-caption-align-right {
35+
text-align: right;
36+
}
37+
38+
.picture-caption-position-top .picture-caption-caption {
39+
margin-bottom: unquote(hexo-config('picture_caption.caption_margin'));
40+
}
41+
42+
.picture-caption-position-bottom .picture-caption-caption {
43+
margin-top: unquote(hexo-config('picture_caption.caption_margin'));
44+
}

0 commit comments

Comments
 (0)