Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions _config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,21 @@ mermaid:
wavedrom:
enable: false

# Picture Caption tag
picture_caption:
picture_border_radius:
enable: false
radius_size: 5px
# Picture gap size between pictures. No strict validation for units; the `px` unit is also acceptable.
picture_gap: 0.5em
# Available caption position: top | bottom
caption_position: bottom
# Available caption alignment: left | center | right
caption_alignment: center
# Caption margin size between picture and caption. No strict validation for units; the `px` unit is also acceptable.
caption_margin: 0.5em
caption_font_size: 0.875em

# ---------------------------------------------------------------
# Third Party Plugins & Services Settings
# See: https://theme-next.js.org/docs/third-party-services/
Expand Down
6 changes: 6 additions & 0 deletions scripts/tags/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ const pdf = require('./pdf')(hexo);

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

const pictureCaption = require('./picture-caption')(hexo);

hexo.extend.tag.register('picturecaption', pictureCaption);
hexo.extend.tag.register('piccap', pictureCaption);
hexo.extend.tag.register('pc', pictureCaption);

const postTabs = require('./tabs')(hexo);

hexo.extend.tag.register('tabs', postTabs, true);
Expand Down
76 changes: 76 additions & 0 deletions scripts/tags/picture-caption.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/**
* picture-caption.js | https://theme-next.js.org/docs/tag-plugins/picture-caption
* Description: Insert an image with caption.
* Usage:
* {% picturecaption pictureUrl, captionText %}
* {% picturecaption pictureUrl, pictureWidth, pictureHeight, captionText, captionUrl, captionIcon, captionPosition, captionAlignment %}
*/

'use strict';

module.exports = ctx => function(args) {
args = args.join(' ').split(',');

const pictureUrl = args[0].trim();
if (!pictureUrl) {
ctx.log.warn('Image URL can NOT be empty in picture-caption tag.');
return '';
}

// Default value.
let pictureWidth = 'auto';
let pictureHeight = 'auto';
let captionText = '';
let captionUrl = '';
let captionIcon = '';
const theme = ctx.theme.config;
let captionPosition = theme.picture_caption.caption_position;
let captionAlignment = theme.picture_caption.caption_alignment;

// Determine the invocation method based on the number of parameters.
if (args.length === 2) {
captionText = args[1].trim() || 'Picture';
} else if (args.length >= 3) {
// Take parameters from back to front.
captionAlignment = ['left', 'center', 'right'].includes(args[args.length - 1].trim()) ? args.pop().trim() : 'center';
captionPosition = ['top', 'bottom'].includes(args[args.length - 1].trim()) ? args.pop().trim() : 'bottom';
captionIcon = args.pop().trim(); // This value can be null.
captionUrl = args.pop().trim(); // This value can be null.
// Take parameters from front to back.
pictureWidth = args[1].trim() || 'auto';
pictureHeight = args[2].trim() || 'auto';
// Allow the captionText to contain English commas, and extract all characters starting from index 3 to the end.
captionText = args.slice(3).join(',') || 'Picture';
}

const style = `width: ${pictureWidth}; height: ${pictureHeight}; object-fit: contain;`;

const imgTag = `<img src="${pictureUrl}" alt="${captionText || 'Picture'}" style="${style}">`;

// Handle captionUrl and captionIcon, default value is null, 'None/none' or empty string is considered as no link.
const hascaptionUrl = captionUrl && captionUrl.toLowerCase() !== 'none';
const hascaptionIcon = captionIcon && captionIcon.toLowerCase() !== 'none';

let captionHtml = '';
if (captionText) {
let captionContent = '';
if (hascaptionIcon) {
if (!captionIcon.startsWith('fa')) { captionIcon = 'fa fa-' + captionIcon; }
captionContent = `<i class="${captionIcon}"></i>${captionText}`;
} else {
captionContent = captionText;
}
if (hascaptionUrl) {
captionContent = `<a href="${captionUrl}" target="_blank">${captionContent}</a>`;
}
captionHtml = `<div class="picture-caption-caption picture-caption-align-${captionAlignment}">${captionContent}</div>`;
}

// Determine the order based on captionPosition.
const content
= captionPosition === 'bottom'
? `${imgTag}${captionHtml}`
: `${captionHtml}${imgTag}`;

return `<div class="picture-caption-container picture-caption-position-${captionPosition}" style="max-width: ${pictureWidth};">${content}</div>`;
};
1 change: 1 addition & 0 deletions source/css/_common/scaffolding/tags/index.styl
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@
@import 'wavedrom';
@import 'note';
@import 'pdf';
@import 'picture-caption';
@import 'tabs';
44 changes: 44 additions & 0 deletions source/css/_common/scaffolding/tags/picture-caption.styl
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
.picture-caption-container {
display: inline-flex;
flex-direction: column;
margin-bottom: 20px;
vertical-align: bottom;
}

.picture-caption-container + .picture-caption-container {
margin-left: unquote(hexo-config('picture_caption.picture_gap'));
}

.picture-caption-container img {
margin: 0 !important;
if(hexo-config('picture_caption.picture_border_radius.enable'))
{
border-radius: unquote(hexo-config('picture_caption.picture_border_radius.radius_size'));
}
}

.picture-caption-caption {
margin: 0;
line-height: 1;
font-size: unquote(hexo-config('picture_caption.caption_font_size'));
}

.picture-caption-align-left {
text-align: left;
}

.picture-caption-align-center {
text-align: center;
}

.picture-caption-align-right {
text-align: right;
}

.picture-caption-position-top .picture-caption-caption {
margin-bottom: unquote(hexo-config('picture_caption.caption_margin'));
}

.picture-caption-position-bottom .picture-caption-caption {
margin-top: unquote(hexo-config('picture_caption.caption_margin'));
}