name:ymc_typora
author:shaw
language:JavaScript && CSS
time:2022.03.15 ~ Now
demo: https://jtcymc.github.io/ymc_typora/
Based on typora-dyzj-theme & drake-juejin theme.
If you are in Mainland China, you can download in Gitee
Stable branch [recommend]:
git clone -b master https://gitee.com/shawymc/ymc_typora.git ymc_typora
Copy theme files to Typora themes folder:
{Typora Install Root Directory}\themes
find {Typora Install Root Directory}\resources\window.html
,search id="write"
go to <div id="write" class="ty-before-first-render" contenteditable="false" spellcheck="true" tabindex="-1">
previously added the following codes:
<script src="https://cdn.jsdelivr.net/gh/jtcymc/ymc_typora@latest/js/autoload-shaw-page-component.min.js"></script>
- Open or Restart Typora. Click on
Themes
to switch toshaw-light
. File
->Preferences
->Export
==>HTML
==>Append in <head/>
add :
<script src="https://cdn.jsdelivr.net/gh/jtcymc/ymc_typora@latest/js/autoload-shaw-page-component.min.js"></script>
- Toolbar:
- BackTop.
- Jump to bottom.
- Change light🔆 / dark🌒 theme.
- Change Live2d model.
- Show or Hide table of Toc.
- Live2d
- Lazyload images. *. Only Support export
HTML
. - Lazyload
iframe
. *. Only Support exportHTML
. - Fasxbox for images. *. Only Support export
HTML
. - FloatBtn for setting:
- Mouse click effect
heart
. - Mouse click effect
firework
. - Mouse trail effect.
- Live2d setting. Includes model selection and switch.
- light🔆 / dark🌒 theme change and sync system theme.
- Others......
- Mouse click effect
Currently, images will be automatically numbered, but to correctly display emoticons (the 'alt' attribute values), additional modifications are required to theframework. jssource code (under the installation pathTypora/resources/appsrc/window
), Navigate to<span class='md image md img loaded "+w+" "+b+"><span class='md meta md front md content edit='true '>"+h+"<span>and<span class='md image "+L+" "data src=" "+k+" "+b+"><span class='md meta md front md content edit='true'>"+h+"<span>
(Note that the relevant code may vary depending on the version of Typora), Replace both ends with the following string:
"<span class='CustomImg' alt='"+ F.getAttribute("alt")+"'>" +F.outerHTML+"</span></span>"
Typora
Theme Settings
/* 导出时才会展示,避免因img标签导致的不生效问题 */
#write p:has(img):not(.md-end-block)::after {
counter-increment: imgNum;
content: "图" counter(imgNum) " " attr(alt) !important;
text-align: center;
width: 100%;
margin-top: 8px !important;
font-size: small;
display: inline-block;
}
/**
* 使用JS实现 给所有 <p><img/></p> 中的p添加alt属性,p的alt值来源 img的alt
* 为了实现导出的图解释
*/
function shaw_img_alt_to_p_label() {
// 获取所有的 <p><img/></p> 元素
const paragraphs = document.querySelectorAll('p > img');
paragraphs.forEach(img => {
const parent = img.parentElement;
const alt = img.getAttribute('alt');
const pAlt = parent.getAttribute('alt');
if (parent && alt && !pAlt) {
// 添加 alt 属性到父元素 p 上
parent.setAttribute('alt', ". " + alt);
}
});
}
window.addEventListener('load', function () {
shaw_img_alt_to_p_label();
});
open {Typora Installation Path}\resources\appsrc\window\frame.js
to find async exportAndSaveHTML(e)
in var n=await this. exportToHTML (e)
Add the following code later:
var regex = /<p[^>]*>\s*<img([^>]+)src=([^>\s]+)(.*?)>\s*<\/p>/gi;
n = n.replace(regex, '<p><img$1data-src=$2$3></p>');
Full code: shaw-typora-expend.js
async exportAndSaveHTML(e) {
var t = await p.showExportDialog("html", e);
if (t) {
this.recordLastExport(e, t);
var n = await this.exportToHTML(e);
// ===========================添加代码============start===========================
var regex = /<p[^>]*>\s*<img([^>]+)src=([^>\s]+)(.*?)>\s*<\/p>/gi;
n = n.replace(regex, '<p><img$1data-src=$2$3></p>');
//n = n.replace(/<iframe src=/g, "<iframe data-src="); // 2023/07/08 添加iframe懒加载
var iframeRegx = /(<iframe\s+[^>]*)(\bsrc\s*=\s*["']?([^>"' ]+)\s*["']?)([^>]*>)/g;
n = n.replace(iframeRegx, `$1 data-src="$3"$4`); // 2023/07/15
// ===========================添加代码============end===========================
File.fs.writeFile(t, n, n => {
n ? (c.showDialog({
title: m.localize.getString("Error"),
html: m.localize.getString("Failed to export file to <em>{0}</em>", "Panel").format(a.escape(t)) + "<br/>" + a.escape(n.message),
backdrop: "static",
type: "error"
}), console.sendError(n, "warn")) : w("html", t, e)
})
}
}
/***
* 优化Typora导出,图片实现懒加载
*/
async function lazyLoadImg(img) {
const intersectionObserver = new IntersectionObserver(
(entries) => {
if (entries[0].isIntersecting) {
const src_tmp = img.getAttribute('data-src');
// 图片进入可视区域,加载图片
// 先保存原始的 src,加载后再替换。
const originalSrc = src_tmp ? src_tmp : "https://hnt-oss.oss-cn-chengdu.aliyuncs.com/js/ui/Not-find-img.png";
img.onload = () => {
// 图片加载完成后移除观察器
intersectionObserver.disconnect();
};
img.src = originalSrc;
}
},
{ threshold: 0.01 }
);
intersectionObserver.observe(img);
}
/**
* iframe 懒加载
* @param iframeTag
*/
async function lazyLoadIframe(iframeTag) {
const intersectionObserver = new IntersectionObserver(
(entries) => {
if (entries[0].isIntersecting) {
const src_tmp = iframeTag.getAttribute("data-src");
// 图片进入可视区域,加载图片
// 先保存原始的 src,加载后再替换。
iframeTag.onload = () => {
// 图片加载完成后移除观察器
intersectionObserver.disconnect();
};
iframeTag.src = src_tmp;
}
},
{ threshold: 0.01 }
);
intersectionObserver.observe(iframeTag);
}
function initLazyLoad() {
const imgs = document.querySelectorAll("p img[data-src]");
imgs.forEach((img) => {
lazyLoadImg(img);
});
// 2023/07/08 添加iframe懒加载 start
const iframeTags = document.querySelectorAll("iframe[data-src]");
iframeTags.forEach((tag) => {
lazyLoadIframe(tag);
});
// 2023/07/08 添加iframe懒加载 end
}
window.addEventListener('load', initLazyLoad);