-
-
Notifications
You must be signed in to change notification settings - Fork 48
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #159 from marp-team/text-color-syntax
Add image syntax for text color
- Loading branch information
Showing
15 changed files
with
399 additions
and
261 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
/** @module */ | ||
import marpitPlugin from './marpit_plugin' | ||
import apply from './image/apply' | ||
import parse from './image/parse' | ||
|
||
/** | ||
* Marpit image plugin. | ||
* | ||
* @alias module:markdown/image | ||
* @param {MarkdownIt} md markdown-it instance. | ||
*/ | ||
function image(md) { | ||
parse(md) | ||
apply(md) | ||
} | ||
|
||
export default marpitPlugin(image) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
/** @module */ | ||
import marpitPlugin from '../marpit_plugin' | ||
import InlineStyle from '../../helpers/inline_style' | ||
|
||
/** | ||
* Marpit image apply plugin. | ||
* | ||
* Apply image style and color spot directive based on parsed meta. | ||
* | ||
* @alias module:markdown/image/apply | ||
* @param {MarkdownIt} md markdown-it instance. | ||
*/ | ||
function applyImage(md) { | ||
// Build and apply image style | ||
md.inline.ruler2.push('marpit_apply_image', ({ tokens }) => { | ||
for (const token of tokens) { | ||
if (token.type === 'image') { | ||
const { filters, height, width } = token.meta.marpitImage | ||
const style = new InlineStyle(token.attrGet('style')) | ||
|
||
if (width && !width.endsWith('%')) style.set('width', width) | ||
if (height && !height.endsWith('%')) style.set('height', height) | ||
|
||
if (filters) { | ||
const filterStyle = [] | ||
|
||
for (const fltrs of filters) | ||
filterStyle.push(`${fltrs[0]}(${fltrs[1]})`) | ||
|
||
token.meta.marpitImage.filter = filterStyle.join(' ') | ||
style.set('filter', token.meta.marpitImage.filter) | ||
} | ||
|
||
const stringified = style.toString() | ||
if (stringified) token.attrSet('style', stringified) | ||
} | ||
} | ||
}) | ||
|
||
// Shorthand for color spot directive | ||
md.core.ruler.after( | ||
'marpit_inline_svg', | ||
'marpit_apply_color', | ||
({ inlineMode, tokens }) => { | ||
if (inlineMode) return | ||
|
||
let current | ||
|
||
for (const t of tokens) { | ||
if (t.type === 'marpit_slide_open') current = t | ||
if (t.type === 'marpit_slide_close') current = undefined | ||
|
||
// Collect parsed inline image meta | ||
if (current && t.type === 'inline') { | ||
for (const tc of t.children) { | ||
if (tc.type === 'image') { | ||
const { background, color } = tc.meta.marpitImage | ||
|
||
if (!background && color) { | ||
current.meta.marpitDirectives = { | ||
...(current.meta.marpitDirectives || {}), | ||
color, | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
) | ||
} | ||
|
||
export default marpitPlugin(applyImage) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
/** @module */ | ||
import colorString from 'color-string' | ||
import marpitPlugin from '../marpit_plugin' | ||
|
||
const escape = target => | ||
target.replace( | ||
/[\\;:()]/g, | ||
matched => `\\${matched[0].codePointAt(0).toString(16)} ` | ||
) | ||
|
||
const optionMatchers = new Map() | ||
|
||
// The scale percentage for resize background | ||
optionMatchers.set(/^(\d*\.)?\d+%$/, matches => ({ size: matches[0] })) | ||
|
||
// width and height | ||
const normalizeLength = v => `${v}${/^(\d*\.)?\d+$/.test(v) ? 'px' : ''}` | ||
|
||
optionMatchers.set( | ||
/^w(?:idth)?:((?:\d*\.)?\d+(?:%|ch|cm|em|ex|in|mm|pc|pt|px)?|auto)$/, | ||
matches => ({ width: normalizeLength(matches[1]) }) | ||
) | ||
|
||
optionMatchers.set( | ||
/^h(?:eight)?:((?:\d*\.)?\d+(?:%|ch|cm|em|ex|in|mm|pc|pt|px)?|auto)$/, | ||
matches => ({ height: normalizeLength(matches[1]) }) | ||
) | ||
|
||
// CSS filters | ||
optionMatchers.set(/^blur(?::(.+))?$/, (matches, meta) => ({ | ||
filters: [...meta.filters, ['blur', escape(matches[1] || '10px')]], | ||
})) | ||
optionMatchers.set(/^brightness(?::(.+))?$/, (matches, meta) => ({ | ||
filters: [...meta.filters, ['brightness', escape(matches[1] || '1.5')]], | ||
})) | ||
optionMatchers.set(/^contrast(?::(.+))?$/, (matches, meta) => ({ | ||
filters: [...meta.filters, ['contrast', escape(matches[1] || '2')]], | ||
})) | ||
optionMatchers.set( | ||
/^drop-shadow(?::(.+?),(.+?)(?:,(.+?))?(?:,(.+?))?)?$/, | ||
(matches, meta) => { | ||
const args = [] | ||
|
||
for (const arg of matches.slice(1)) { | ||
if (arg) { | ||
const colorFunc = arg.match(/^(rgba?|hsla?)\((.*)\)$/) | ||
|
||
args.push( | ||
colorFunc ? `${colorFunc[1]}(${escape(colorFunc[2])})` : escape(arg) | ||
) | ||
} | ||
} | ||
|
||
return { | ||
filters: [ | ||
...meta.filters, | ||
['drop-shadow', args.join(' ') || '0 5px 10px rgba(0,0,0,.4)'], | ||
], | ||
} | ||
} | ||
) | ||
optionMatchers.set(/^grayscale(?::(.+))?$/, (matches, meta) => ({ | ||
filters: [...meta.filters, ['grayscale', escape(matches[1] || '1')]], | ||
})) | ||
optionMatchers.set(/^hue-rotate(?::(.+))?$/, (matches, meta) => ({ | ||
filters: [...meta.filters, ['hue-rotate', escape(matches[1] || '180deg')]], | ||
})) | ||
optionMatchers.set(/^invert(?::(.+))?$/, (matches, meta) => ({ | ||
filters: [...meta.filters, ['invert', escape(matches[1] || '1')]], | ||
})) | ||
optionMatchers.set(/^opacity(?::(.+))?$/, (matches, meta) => ({ | ||
filters: [...meta.filters, ['opacity', escape(matches[1] || '.5')]], | ||
})) | ||
optionMatchers.set(/^saturate(?::(.+))?$/, (matches, meta) => ({ | ||
filters: [...meta.filters, ['saturate', escape(matches[1] || '2')]], | ||
})) | ||
optionMatchers.set(/^sepia(?::(.+))?$/, (matches, meta) => ({ | ||
filters: [...meta.filters, ['sepia', escape(matches[1] || '1')]], | ||
})) | ||
|
||
/** | ||
* Marpit image parse plugin. | ||
* | ||
* Parse image tokens and store the result into `marpitImage` meta. It has an | ||
* image url and options. The alternative text is regarded as space-separated | ||
* options. | ||
* | ||
* @alias module:markdown/image/parse | ||
* @param {MarkdownIt} md markdown-it instance. | ||
*/ | ||
function parseImage(md) { | ||
md.inline.ruler2.push('marpit_parse_image', ({ tokens }) => { | ||
for (const token of tokens) { | ||
if (token.type === 'image') { | ||
const options = token.content.split(/\s+/).filter(s => s.length > 0) | ||
const url = token.attrGet('src') | ||
|
||
token.meta = token.meta || {} | ||
token.meta.marpitImage = { | ||
...(token.meta.marpitImage || {}), | ||
url, | ||
options, | ||
} | ||
|
||
// Detect shorthand for setting color | ||
if (!!colorString.get(url) || url.toLowerCase() === 'currentcolor') { | ||
token.meta.marpitImage.color = url | ||
token.hidden = true | ||
} | ||
|
||
// Parse keyword through matchers | ||
for (const opt of options) { | ||
for (const [regexp, mergeFunc] of optionMatchers) { | ||
const matched = opt.match(regexp) | ||
|
||
if (matched) | ||
token.meta.marpitImage = { | ||
...token.meta.marpitImage, | ||
...mergeFunc(matched, { | ||
filters: [], | ||
...token.meta.marpitImage, | ||
}), | ||
} | ||
} | ||
} | ||
} | ||
} | ||
}) | ||
} | ||
|
||
export default marpitPlugin(parseImage) |
Oops, something went wrong.