diff --git a/README.md b/README.md index ec7ea5c..570c610 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ 预览:[https://sivan.github.io/heti/](https://sivan.github.io/heti/) +![Preview](https://raw.githubusercontent.com/sivan/heti/master/_site/assets/screenshot-grid.png) + 主要特性: - 贴合网格的排版; - 全标签样式美化; @@ -11,7 +13,7 @@ - 预置多种排版样式(行间注、多栏、竖排等); - 多种预设字体族(仅限桌面端); - 简/繁体中文支持; -- 中西文混排美化(基于JavaScript脚本实现); +- 中西文混排美化,不再手敲空格👏(基于JavaScript脚本); - 兼容 *normalize.css*、*CSS Reset* 等常见样式重置; - 移动端支持; - …… @@ -36,8 +38,8 @@ ## WIP -- [ ] 标点挤压 -- [ ] 标点悬挂 +- [ ] 自适应黑暗模式 +- [x] 标点挤压 - [x] 中、西文混排 - [x] 繁体中文支持 - [x] 诗词版式 diff --git a/_site/assets/screenshot-grid.png b/_site/assets/screenshot-grid.png new file mode 100644 index 0000000..188592c Binary files /dev/null and b/_site/assets/screenshot-grid.png differ diff --git a/_site/assets/screenshot.png b/_site/assets/screenshot.png new file mode 100644 index 0000000..d1d17cc Binary files /dev/null and b/_site/assets/screenshot.png differ diff --git a/_site/heti-addon.js b/_site/heti-addon.js index 0941953..92ccf46 100644 --- a/_site/heti-addon.js +++ b/_site/heti-addon.js @@ -654,28 +654,32 @@ * Add right spacing between CJK & ANS characters */ - // 正则表达式来自 pangu.js https://github.com/vinta/pangu.js - const CJK = '\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30fa\u30fc-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff'; - const A = 'A-Za-z\u0370-\u03ff'; - const N = '0-9'; - const S = '`~!@#\\$%\\^&\\*\\(\\)-_=\\+\\[\\]{}\\\\\\|;:\'",<.>\\/\\?'; - const ANS = `${A}${N}${S}`; + const hasOwn = {}.hasOwnProperty; const HETI_NON_CONTIGUOUS_ELEMENTS = Object.assign({}, findAndReplaceDOMText.NON_CONTIGUOUS_PROSE_ELEMENTS, { - // Inline elements ins: 1, del: 1, s: 1, }); const HETI_SKIPPED_ELEMENTS = Object.assign({}, findAndReplaceDOMText.NON_PROSE_ELEMENTS, { - pre: 1, code: 1, sup: 1, sub: 1, - // Heti elements - 'heti-spacing': 1, + pre: 1, code: 1, sup: 1, sub: 1, 'heti-spacing': 1, 'heti-close': 1, }); const HETI_SKIPPED_CLASS = 'heti-skip'; - const hasOwn = {}.hasOwnProperty; - const REG_FULL = `(?<=[${CJK}])( *[${ANS}]+(?: +[${ANS}]+)* *)(?=[${CJK}])`; - const REG_FULL_FIX = `(?:[${CJK}])( *[${ANS}]+(?: +[${ANS}]+)* *)(?=[${CJK}])`; - const REG_START = `([${ANS}]+(?: +[${ANS}]+)* *)(?=[${CJK}])`; - const REG_END = `(?<=[${CJK}])( *[${ANS}]+(?: +[${ANS}]+)*)`; - const REG_END_FIX = `(?:[${CJK}])( *[${ANS}]+(?: +[${ANS}]+)*)`; + + // 部分正则表达式修改自 pangu.js https://github.com/vinta/pangu.js + const CJK = '\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30fa\u30fc-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff'; + const A = 'A-Za-z\u0080-\u00ff\u0370-\u03ff'; + const N = '0-9'; + const S = '`~!@#\\$%\\^&\\*\\(\\)-_=\\+\\[\\]{}\\\\\\|;:\'",<.>\\/\\?'; + const ANS = `${A}${N}${S}`; + const REG_CJK_FULL = `(?<=[${CJK}])( *[${ANS}]+(?: +[${ANS}]+)* *)(?=[${CJK}])`; + const REG_CJK_START = `([${ANS}]+(?: +[${ANS}]+)* *)(?=[${CJK}])`; + const REG_CJK_END = `(?<=[${CJK}])( *[${ANS}]+(?: +[${ANS}]+)*)`; + const REG_CJK_FULL_WITHOUT_LOOKBEHIND = `(?:[${CJK}])( *[${ANS}]+(?: +[${ANS}]+)* *)(?=[${CJK}])`; + const REG_CJK_END_WITHOUT_LOOKBEHIND = `(?:[${CJK}])( *[${ANS}]+(?: +[${ANS}]+)*)`; + const REG_BD_STOP = `。.,、:;!‼?⁇`; + const REG_BD_SEP = `·・‧`; + const REG_BD_OPEN = `「『(《〈【〖〔[{`; + const REG_BD_CLOSE = `」』)》〉】〗〕]}`; + const REG_BD_START = `${REG_BD_OPEN}${REG_BD_CLOSE}`; + const REG_BD_END = `${REG_BD_STOP}${REG_BD_OPEN}${REG_BD_CLOSE}`; class Heti { constructor (rootSelector) { @@ -689,13 +693,12 @@ } this.rootSelector = rootSelector || '.heti'; - this.REG_FULL = new RegExp(supportLookBehind ? REG_FULL : REG_FULL_FIX, 'g'); - this.REG_START = new RegExp(REG_START, 'g'); - this.REG_END = new RegExp(supportLookBehind ? REG_END : REG_END_FIX, 'g'); + this.REG_FULL = new RegExp(supportLookBehind ? REG_CJK_FULL : REG_CJK_FULL_WITHOUT_LOOKBEHIND, 'g'); + this.REG_START = new RegExp(REG_CJK_START, 'g'); + this.REG_END = new RegExp(supportLookBehind ? REG_CJK_END : REG_CJK_END_WITHOUT_LOOKBEHIND, 'g'); this.offsetWidth = supportLookBehind ? 0 : 1; this.funcForceContext = function forceContext (el) { return hasOwn.call(HETI_NON_CONTIGUOUS_ELEMENTS, el.nodeName.toLowerCase()) - // return true }; this.funcFilterElements = function filterElements (el) { return ( @@ -716,8 +719,8 @@ forceContext: this.funcForceContext, filterElements: this.funcFilterElements, }; - const getWrapper = function (classList, text) { - const $$r = document.createElement('heti-spacing'); + const getWrapper = function (elementName, classList, text) { + const $$r = document.createElement(elementName); $$r.className = classList; $$r.textContent = text.trim(); return $$r @@ -725,18 +728,30 @@ findAndReplaceDOMText($$elm, Object.assign({}, commonConfig, { find: this.REG_FULL, - replace: portion => getWrapper('heti-spacing-start heti-spacing-end', portion.text), + replace: portion => getWrapper('heti-spacing', 'heti-spacing-start heti-spacing-end', portion.text), offset: this.offsetWidth, })); findAndReplaceDOMText($$elm, Object.assign({}, commonConfig, { find: this.REG_START, - replace: portion => getWrapper('heti-spacing-start', portion.text), + replace: portion => getWrapper('heti-spacing', 'heti-spacing-start', portion.text), })); findAndReplaceDOMText($$elm, Object.assign({}, commonConfig, { find: this.REG_END, - replace: portion => getWrapper('heti-spacing-end', portion.text), + replace: portion => getWrapper('heti-spacing', 'heti-spacing-end', portion.text), + offset: this.offsetWidth, + })); + + findAndReplaceDOMText($$elm, Object.assign({}, commonConfig, { + find: new RegExp(`([${REG_BD_STOP}])(?=[${REG_BD_START}])|([${REG_BD_OPEN}])(?=[${REG_BD_OPEN}])|([${REG_BD_CLOSE}])(?=[${REG_BD_END}])`,'g'), + replace: portion => getWrapper('heti-adjacent', 'heti-adjacent-half', portion.text), + offset: this.offsetWidth, + })); + + findAndReplaceDOMText($$elm, Object.assign({}, commonConfig, { + find: new RegExp(`([${REG_BD_SEP}])(?=[${REG_BD_OPEN}])|([${REG_BD_CLOSE}])(?=[${REG_BD_SEP}])`,'g'), + replace: portion => getWrapper('heti-adjacent', 'heti-adjacent-quarter', portion.text), offset: this.offsetWidth, })); } diff --git a/_site/heti.css b/_site/heti.css index bc7c320..f5372ce 100644 --- a/_site/heti.css +++ b/_site/heti.css @@ -802,3 +802,15 @@ .heti .heti-spacing-end { margin-inline-start: 0.25em; } + +.heti heti-adjacent { + display: inline; +} + +.heti .heti-adjacent-half { + margin-inline-end: -0.5em; +} + +.heti .heti-adjacent-quarter { + margin-inline-end: -0.25em; +} diff --git a/_site/index.html b/_site/index.html index 959945f..76e4260 100644 --- a/_site/index.html +++ b/_site/index.html @@ -13,7 +13,7 @@

赫蹏

-
古代称用以书写的小幅绢帛。后亦以借指纸。《汉书·外戚传下·孝成赵皇后》:武(籍武 )发篋中,有裹药二枚,赫蹏书。颜师古注:邓展曰:赫音兄弟鬩墙之鬩。应劭曰:赫蹏,薄小纸也。赵彦卫 《云麓漫钞》卷七:《赵后传》所谓『赫蹏』者,注云薄小纸,然其寔亦縑帛。
+
古代称用以书写的小幅绢帛。后亦以借指纸。《汉书·外戚传下·孝成赵皇后》:「武(籍武 )发篋中,有裹药二枚,赫蹏书。」颜师古注:「邓展曰:『赫音兄弟鬩墙之鬩。』应劭曰:『赫蹏,薄小纸也。』」赵彦卫 《云麓漫钞》卷七:「《赵后传》所谓『赫蹏』者,注云『薄小纸』,然其寔亦縑帛。」
diff --git a/js/heti-addon.js b/js/heti-addon.js index dac6b6c..81e5ea2 100644 --- a/js/heti-addon.js +++ b/js/heti-addon.js @@ -5,28 +5,32 @@ import Finder from 'heti-findandreplacedomtext' -// 正则表达式来自 pangu.js https://github.com/vinta/pangu.js -const CJK = '\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30fa\u30fc-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff' -const A = 'A-Za-z\u0370-\u03ff' -const N = '0-9' -const S = '`~!@#\\$%\\^&\\*\\(\\)-_=\\+\\[\\]{}\\\\\\|;:\'",<.>\\/\\?' -const ANS = `${A}${N}${S}` +const hasOwn = {}.hasOwnProperty const HETI_NON_CONTIGUOUS_ELEMENTS = Object.assign({}, Finder.NON_CONTIGUOUS_PROSE_ELEMENTS, { - // Inline elements ins: 1, del: 1, s: 1, }) const HETI_SKIPPED_ELEMENTS = Object.assign({}, Finder.NON_PROSE_ELEMENTS, { - pre: 1, code: 1, sup: 1, sub: 1, - // Heti elements - 'heti-spacing': 1, + pre: 1, code: 1, sup: 1, sub: 1, 'heti-spacing': 1, 'heti-close': 1, }) const HETI_SKIPPED_CLASS = 'heti-skip' -const hasOwn = {}.hasOwnProperty -const REG_FULL = `(?<=[${CJK}])( *[${ANS}]+(?: +[${ANS}]+)* *)(?=[${CJK}])` -const REG_FULL_FIX = `(?:[${CJK}])( *[${ANS}]+(?: +[${ANS}]+)* *)(?=[${CJK}])` -const REG_START = `([${ANS}]+(?: +[${ANS}]+)* *)(?=[${CJK}])` -const REG_END = `(?<=[${CJK}])( *[${ANS}]+(?: +[${ANS}]+)*)` -const REG_END_FIX = `(?:[${CJK}])( *[${ANS}]+(?: +[${ANS}]+)*)` + +// 部分正则表达式修改自 pangu.js https://github.com/vinta/pangu.js +const CJK = '\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30fa\u30fc-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff' +const A = 'A-Za-z\u0080-\u00ff\u0370-\u03ff' +const N = '0-9' +const S = '`~!@#\\$%\\^&\\*\\(\\)-_=\\+\\[\\]{}\\\\\\|;:\'",<.>\\/\\?' +const ANS = `${A}${N}${S}` +const REG_CJK_FULL = `(?<=[${CJK}])( *[${ANS}]+(?: +[${ANS}]+)* *)(?=[${CJK}])` +const REG_CJK_START = `([${ANS}]+(?: +[${ANS}]+)* *)(?=[${CJK}])` +const REG_CJK_END = `(?<=[${CJK}])( *[${ANS}]+(?: +[${ANS}]+)*)` +const REG_CJK_FULL_WITHOUT_LOOKBEHIND = `(?:[${CJK}])( *[${ANS}]+(?: +[${ANS}]+)* *)(?=[${CJK}])` +const REG_CJK_END_WITHOUT_LOOKBEHIND = `(?:[${CJK}])( *[${ANS}]+(?: +[${ANS}]+)*)` +const REG_BD_STOP = `。.,、:;!‼?⁇` +const REG_BD_SEP = `·・‧` +const REG_BD_OPEN = `「『(《〈【〖〔[{` +const REG_BD_CLOSE = `」』)》〉】〗〕]}` +const REG_BD_START = `${REG_BD_OPEN}${REG_BD_CLOSE}` +const REG_BD_END = `${REG_BD_STOP}${REG_BD_OPEN}${REG_BD_CLOSE}` class Heti { constructor (rootSelector) { @@ -40,13 +44,12 @@ class Heti { } this.rootSelector = rootSelector || '.heti' - this.REG_FULL = new RegExp(supportLookBehind ? REG_FULL : REG_FULL_FIX, 'g') - this.REG_START = new RegExp(REG_START, 'g') - this.REG_END = new RegExp(supportLookBehind ? REG_END : REG_END_FIX, 'g') + this.REG_FULL = new RegExp(supportLookBehind ? REG_CJK_FULL : REG_CJK_FULL_WITHOUT_LOOKBEHIND, 'g') + this.REG_START = new RegExp(REG_CJK_START, 'g') + this.REG_END = new RegExp(supportLookBehind ? REG_CJK_END : REG_CJK_END_WITHOUT_LOOKBEHIND, 'g') this.offsetWidth = supportLookBehind ? 0 : 1 this.funcForceContext = function forceContext (el) { return hasOwn.call(HETI_NON_CONTIGUOUS_ELEMENTS, el.nodeName.toLowerCase()) - // return true } this.funcFilterElements = function filterElements (el) { return ( @@ -67,8 +70,8 @@ class Heti { forceContext: this.funcForceContext, filterElements: this.funcFilterElements, } - const getWrapper = function (classList, text) { - const $$r = document.createElement('heti-spacing') + const getWrapper = function (elementName, classList, text) { + const $$r = document.createElement(elementName) $$r.className = classList $$r.textContent = text.trim() return $$r @@ -76,18 +79,30 @@ class Heti { Finder($$elm, Object.assign({}, commonConfig, { find: this.REG_FULL, - replace: portion => getWrapper('heti-spacing-start heti-spacing-end', portion.text), + replace: portion => getWrapper('heti-spacing', 'heti-spacing-start heti-spacing-end', portion.text), offset: this.offsetWidth, })) Finder($$elm, Object.assign({}, commonConfig, { find: this.REG_START, - replace: portion => getWrapper('heti-spacing-start', portion.text), + replace: portion => getWrapper('heti-spacing', 'heti-spacing-start', portion.text), })) Finder($$elm, Object.assign({}, commonConfig, { find: this.REG_END, - replace: portion => getWrapper('heti-spacing-end', portion.text), + replace: portion => getWrapper('heti-spacing', 'heti-spacing-end', portion.text), + offset: this.offsetWidth, + })) + + Finder($$elm, Object.assign({}, commonConfig, { + find: new RegExp(`([${REG_BD_STOP}])(?=[${REG_BD_START}])|([${REG_BD_OPEN}])(?=[${REG_BD_OPEN}])|([${REG_BD_CLOSE}])(?=[${REG_BD_END}])`,'g'), + replace: portion => getWrapper('heti-adjacent', 'heti-adjacent-half', portion.text), + offset: this.offsetWidth, + })) + + Finder($$elm, Object.assign({}, commonConfig, { + find: new RegExp(`([${REG_BD_SEP}])(?=[${REG_BD_OPEN}])|([${REG_BD_CLOSE}])(?=[${REG_BD_SEP}])`,'g'), + replace: portion => getWrapper('heti-adjacent', 'heti-adjacent-quarter', portion.text), offset: this.offsetWidth, })) } diff --git a/lib/helpers/_add-on.scss b/lib/helpers/_add-on.scss index cca3155..0c8e053 100644 --- a/lib/helpers/_add-on.scss +++ b/lib/helpers/_add-on.scss @@ -20,4 +20,16 @@ .heti-spacing-end { margin-inline-start: 0.25em; } + + heti-adjacent { + display: inline; + } + + .heti-adjacent-half { + margin-inline-end: -0.5em; + } + + .heti-adjacent-quarter { + margin-inline-end: -0.25em; + } } diff --git a/package-lock.json b/package-lock.json index 237d115..fb61212 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "heti", - "version": "0.5.0", + "version": "0.6.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 9a27876..d5ae0bd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "heti", - "version": "0.5.0", + "version": "0.6.0", "description": "赫蹏是专为中文内容展示设计的排版样式增强。它基于通行的中文排版规范而来,可以为网站的读者带来更好的文章阅读体验。", "main": "lib/heti.scss", "files": [