aardio 文档

aardio 范例: HTML 富文本复制工具

import fonts.fontAwesome;
import win.clip;
import string.html;
import win.ui;
/*DSG{{*/
var winform = win.form(text="HTML 富文本复制工具";right=900;bottom=650;bgcolor=0xF5F2ED)
winform.add(
bk={cls="bk";left=7;top=124;right=268;bottom=585;anchors={left=1;top=1};bgcolor=0xFAF7F2;z=1};
bk2={cls="bk";left=7;top=4;right=881;bottom=151;anchors={top=1;right=1;bottom=1};bgcolor=0xE49D46;forecolor=0xE19942;linearGradient=1;z=3};
bk3={cls="bk";left=7;top=585;right=881;bottom=647;anchors={left=1;right=1;bottom=1};bgcolor=0xFFFFFF;z=2};
btnCopy={cls="button";text="复制到剪贴板";left=621;top=589;right=837;bottom=636;anchors={right=1;bottom=1};bgcolor=0xFFFFFF;color=0xE19942;font=LOGFONT(h=-14;weight=600);note="可直接粘贴到在线编辑器";z=10};
checkWechat={cls="plus";text="微信兼容输出";left=708;top=117;right=847;bottom=148;align="left";color=0xFFFFFF;font=LOGFONT(h=-15);iconStyle={align="left";font=LOGFONT(h=-15;name='FontAwesome')};iconText='\uF0C8 ';textPadding={left=24};z=40};
edit={cls="edit";text="F5";left=16;top=48;right=870;bottom=110;anchors={top=1;right=1;bottom=1};autohscroll=false;edge=1;font=LOGFONT(h=-14);multiline=1;z=11};
groupPreview={cls="custom";text="预览区域";left=278;top=158;right=878;bottom=576;anchors={left=1;top=1;right=1;bottom=1};bgcolor=0xFFFFFF;edge=1;z=4};
lnkCodeBlock={cls="syslink";text='<a href="#">通用代码块复制工具</a>';left=16;top=614;right=158;bottom=638;anchors={left=1;bottom=1};bgcolor=0xFFFFFF;font=LOGFONT(h=-13);notify=1;z=5};
radio3D={cls="radiobutton";text="3D 立体";left=19;top=388;right=139;bottom=412;anchors={left=1;top=1};bgcolor=0xFAF7F2;font=LOGFONT(h=-13);tabstop=1;z=20};
radioBadge={cls="radiobutton";text="信息徽章";left=19;top=331;right=139;bottom=355;anchors={left=1;top=1};bgcolor=0xFAF7F2;font=LOGFONT(h=-13);tabstop=1;z=32};
radioBrutalism={cls="radiobutton";text="波普";left=19;top=532;right=139;bottom=556;anchors={left=1;top=1};bgcolor=0xFAF7F2;font=LOGFONT(h=-13);tabstop=1;z=34};
radioChatA1={cls="radiobutton";text="极简线框答";left=146;top=446;right=266;bottom=470;anchors={left=1;top=1};bgcolor=0xFAF7F2;font=LOGFONT(h=-13);tabstop=1;z=37};
radioChatQ1={cls="radiobutton";text="极简线框问";left=146;top=417;right=266;bottom=441;anchors={left=1;top=1};bgcolor=0xFAF7F2;font=LOGFONT(h=-13);tabstop=1;z=36};
radioCodeTitle={cls="radiobutton";text="代码块标题";left=146;top=302;right=266;bottom=326;anchors={left=1;top=1};bgcolor=0xFAF7F2;font=LOGFONT(h=-13);tabstop=1;z=24};
radioComment={cls="radiobutton";text="代码块";left=146;top=273;right=266;bottom=297;anchors={left=1;top=1};bgcolor=0xFAF7F2;font=LOGFONT(h=-13);tabstop=1;z=23};
radioCyberpunk={cls="radiobutton";text="赛博朋克";left=19;top=561;right=139;bottom=585;anchors={left=1;top=1};bgcolor=0xFAF7F2;font=LOGFONT(h=-13);tabstop=1;z=33};
radioError={cls="radiobutton";text="错误提示";left=146;top=216;right=266;bottom=240;anchors={left=1;top=1};bgcolor=0xFAF7F2;font=LOGFONT(h=-13);tabstop=1;z=31};
radioGitHub={cls="radiobutton";text="GitHub 风格";left=146;top=388;right=266;bottom=412;anchors={left=1;top=1};bgcolor=0xFAF7F2;font=LOGFONT(h=-13);tabstop=1;z=13};
radioGlass={cls="radiobutton";text="玻璃态";left=19;top=359;right=139;bottom=383;anchors={left=1;top=1};bgcolor=0xFAF7F2;font=LOGFONT(h=-13);tabstop=1;z=26};
radioGradient={cls="radiobutton";text="现代渐变";left=19;top=273;right=139;bottom=297;anchors={left=1;top=1};bgcolor=0xFAF7F2;font=LOGFONT(h=-13);tabstop=1;z=17};
radioHighlighter={cls="radiobutton";text="荧光笔";left=19;top=446;right=139;bottom=470;anchors={left=1;top=1};bgcolor=0xFAF7F2;font=LOGFONT(h=-13);tabstop=1;z=22};
radioHotkey={cls="radiobutton";text="热键样式";left=146;top=475;right=266;bottom=499;anchors={left=1;top=1};bgcolor=0xFAF7F2;checked=1;font=LOGFONT(h=-13);tabstop=1;z=12};
radioLego={cls="radiobutton";text="乐高积木";left=19;top=503;right=139;bottom=527;anchors={left=1;top=1};bgcolor=0xFAF7F2;font=LOGFONT(h=-13);tabstop=1;z=38};
radioMacTag={cls="radiobutton";text="macOS 标签";left=19;top=158;right=139;bottom=182;anchors={left=1;top=1};bgcolor=0xFAF7F2;font=LOGFONT(h=-13);tabstop=1;z=30};
radioMedium={cls="radiobutton";text="Medium 风格";left=19;top=244;right=139;bottom=268;anchors={left=1;top=1};bgcolor=0xFAF7F2;font=LOGFONT(h=-13);tabstop=1;z=16};
radioNeon={cls="radiobutton";text="霓虹发光";left=19;top=187;right=139;bottom=211;anchors={left=1;top=1};bgcolor=0xFAF7F2;font=LOGFONT(h=-13);z=25};
radioNeumorphism={cls="radiobutton";text="新拟态";left=19;top=215;right=139;bottom=239;anchors={left=1;top=1};bgcolor=0xFAF7F2;font=LOGFONT(h=-13);tabstop=1;z=27};
radioPixel={cls="radiobutton";text="像素游戏";left=19;top=475;right=139;bottom=499;anchors={left=1;top=1};bgcolor=0xFAF7F2;font=LOGFONT(h=-13);tabstop=1;z=35};
radioQuote={cls="radiobutton";text="引用块";left=146;top=503;right=266;bottom=527;anchors={left=1;top=1};bgcolor=0xFAF7F2;font=LOGFONT(h=-13);tabstop=1;z=39};
radioRainbow={cls="radiobutton";text="彩虹渐变";left=19;top=302;right=139;bottom=326;anchors={left=1;top=1};bgcolor=0xFAF7F2;font=LOGFONT(h=-13);tabstop=1;z=28};
radioStackOverflow={cls="radiobutton";text="Stack Overflow";left=146;top=331;right=266;bottom=355;anchors={left=1;top=1};bgcolor=0xFAF7F2;font=LOGFONT(h=-13);tabstop=1;z=15};
radioSuccess={cls="radiobutton";text="成功提示";left=146;top=158;right=266;bottom=182;anchors={left=1;top=1};bgcolor=0xFAF7F2;font=LOGFONT(h=-13);tabstop=1;z=19};
radioTerminal={cls="radiobutton";text="终端样式";left=146;top=244;right=266;bottom=268;anchors={left=1;top=1};bgcolor=0xFAF7F2;font=LOGFONT(h=-13);tabstop=1;z=29};
radioTypewriter={cls="radiobutton";text="复古打字机";left=19;top=417;right=139;bottom=441;anchors={left=1;top=1};bgcolor=0xFAF7F2;font=LOGFONT(h=-13);tabstop=1;z=21};
radioVSCode={cls="radiobutton";text="VS Code 深色";left=146;top=360;right=266;bottom=384;anchors={left=1;top=1};bgcolor=0xFAF7F2;font=LOGFONT(h=-13);tabstop=1;z=14};
radioWarning={cls="radiobutton";text="警告提示";left=146;top=187;right=266;bottom=211;anchors={left=1;top=1};bgcolor=0xFAF7F2;font=LOGFONT(h=-13);tabstop=1;z=18};
static={cls="static";text="输入需要添加样式的文本:";left=16;top=16;right=184;bottom=39;anchors={left=1;top=1};color=0xFFFFFF;font=LOGFONT(h=-13;weight=500);transparent=1;z=6};
static2={cls="static";text="字体大小:";left=16;top=120;right=90;bottom=143;anchors={left=1;top=1};color=0xFFFFFF;font=LOGFONT(h=-13;weight=500);transparent=1;z=7};
syslink={cls="syslink";text='<a href="http://gif123.aardio.com">Gif123 动画复制工具</a>';left=167;top=614;right=317;bottom=638;anchors={left=1;bottom=1};bgcolor=0xFFFFFF;font=LOGFONT(h=-13);notify=1;z=9};
tbFontSize={cls="plus";left=97;top=124;right=680;bottom=139;anchors={top=1;right=1;bottom=1};bgcolor=0x4299E1;border={radius=-1};color=0xFFFFFF;foreRight=15;forecolor=0xEECF5B;notify=1;paddingBottom=5;paddingTop=5;z=8}
)
/*}}*/

import web.form;
var wb = web.form(winform.groupPreview);
wb.noScriptErr = true;

// 样式模板
var styles = {

    // 热键样式
    hotkey = `<kbd style="display:inline;background-color: #2572cb !important ;color: #FFF !important;border-radius: 4px !important ; box-shadow: 0px 3px 0px 1px silver !important ; padding: 4px 8px; margin: 0 4px; font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', 'Courier New', monospace; font-size: %s;  font-weight: bold;text-align: center;text-transform: uppercase; white-space: nowrap;">%s</kbd>`;

    // GitHub 风格
    github = `<code style="display:inline;white-space:pre-wrap;background-color: #f6f8fa; padding: 2px 6px; border-radius: 3px; font-family: 'Consolas', 'Monaco', 'Courier New', monospace; font-size: %s; color: #24292f; border: 1px solid #d0d7de;">%s</code>`;

    // VSC 风格
    vscode = `<code style="display:inline;white-space:pre-wrap;background-color: #1e1e1e; padding: 3px 8px; border-radius: 4px; font-family: 'Fira Code', 'Consolas', monospace; font-size: %s; color: #d4d4d4;">%s</code>`;

    // SO 风格
    stackoverflow = `<code style="display:inline;white-space:pre-wrap;background-color: #e4e6e8; padding: 2px 5px; border-radius: 3px; font-family: 'Courier New', Courier, monospace; font-size: %s; color: #2d2d2d;">%s</code>`;

    // Medium 风格
    medium = `<code style="display:inline;white-space:pre-wrap;background-color: rgba(0,0,0,0.05); padding: 3px 6px; border-radius: 2px; font-family: Menlo, Monaco, monospace; font-size: %s; color: #292929;">%s</code>`;

    // 现代渐变
    gradient = `<code style="display:inline;white-space:pre-wrap;background: linear-gradient(135deg, #667eea 0%%, #764ba2 100%%); padding: 3px 8px; border-radius: 5px; font-family: 'Fira Code', monospace; font-size: %s; color: #ffffff; font-weight: 500;">%s</code>`;

    // 霓虹发光效果
    neon = `<code style="display:inline;white-space:pre-wrap;background-color: #0a0e27; padding: 5px 12px; border-radius: 6px; font-family: 'Courier New', monospace; font-size: %s; color: #fff; text-shadow: 0 0 10px #00fff2, 0 0 20px #00fff2, 0 0 30px #00fff2; border: 2px solid #00fff2; box-shadow: inset 0 0 10px rgba(0, 255, 242, 0.3), 0 0 20px rgba(0, 255, 242, 0.5);">%s</code>`;

    // 玻璃态效果
    glass = `<code style="display:inline;white-space:pre-wrap;background: rgba(255, 255, 255, 0.25); backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); padding: 4px 10px; border-radius: 8px; font-family: 'SF Pro Display', -apple-system, monospace; font-size: %s; color: #1a1a1a; border: 1px solid rgba(255, 255, 255, 0.5); box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);">%s</code>`;

    // 新拟态效果
    neumorphism = `<code style="display:inline;white-space:pre-wrap;background: #e0e5ec; padding: 6px 14px; border-radius: 10px; font-family: 'Segoe UI', monospace; font-size: %s; color: #4a5568; box-shadow: 9px 9px 16px #a3a9b3, -9px -9px 16px #ffffff; font-weight: 500;">%s</code>`;

    // 彩虹渐变
    rainbow = `<code style="display:inline;white-space:pre-wrap;background: linear-gradient(90deg, #ff6b6b, #ffd93d, #6bcf7f, #4ecdc4, #4e89e3, #9b59b6); padding: 4px 10px; border-radius: 6px; font-family: 'Comic Sans MS', cursive; font-size: %s; color: #ffffff; font-weight: bold; text-shadow: 1px 1px 2px rgba(0,0,0,0.3);">%s</code>`;

    // 终端样式
    terminal = `<code style="display:inline;white-space:pre-wrap;white-space:pre-wrap; background: #000000; padding: 5px 10px; border-radius: 4px; font-family: 'Fira Code', 'Consolas', monospace; font-size: %s; color: #00ff00; border-left: 3px solid #00ff00; box-shadow: 0 2px 4px rgba(0,0,0,0.3);">$ %s</code>`;

    // macOS 标签样式
    macTag = `<span style="display:inline;white-space:pre-wrap;background: linear-gradient(180deg, #5e5ce6 0%%, #4a4ae6 100%%); padding: 3px 10px; border-radius: 12px; font-family: -apple-system, BlinkMacSystemFont, sans-serif; font-size: %s; color: #ffffff; font-weight: 500; box-shadow: 0 2px 4px rgba(94, 92, 230, 0.3);">%s</span>`;

    // 警告提示样式
    warning = `<mark style="display:inline;white-space:pre-wrap;background: linear-gradient(135deg, #ffd700 0%%, #ffb347 100%%); padding: 2px 8px; border-radius: 4px; font-family: 'Helvetica Neue', Arial, sans-serif; font-size: %s; color: #663300; font-weight: 600; box-shadow: 0 2px 4px rgba(255, 183, 71, 0.3);">⚠️ %s</mark>`;

    // 成功提示样式
    success = `<span style="display:inline;background: linear-gradient(135deg, #84fab0 0%%, #8fd3f4 100%%); padding: 3px 10px; border-radius: 5px; font-family: 'Segoe UI', Tahoma, sans-serif; font-size: %s; color: #155724; font-weight: 500; border: 1px solid rgba(132, 250, 176, 0.5);">✓ %s</span>`;

    // 3D 立体效果
    three3d = `<code style="display:inline;white-space:pre-wrap;background: #f4f4f4; padding: 5px 12px; border-radius: 4px; font-family: 'Impact', sans-serif; font-size: %s; color: #333; text-shadow: 1px 1px 0px #fff, 2px 2px 0px #b0b0b0, 3px 3px 0px #c0c0c0; font-weight: bold; transform: perspective(500px) rotateY(-5deg);">%s</code>`;

    // 复古打字机效果
    typewriter = `<code style="display:inline;white-space:pre-wrap;background: #fffef0; padding: 4px 8px; border: 2px solid #3a3a3a; border-radius: 2px; font-family: 'Courier Prime', 'Courier', monospace; font-size: %s; color: #2a2a2a; box-shadow: 2px 2px 0px #3a3a3a; font-weight: 400; letter-spacing: 0.05em;">%s</code>`;

    // 荧光笔标记效果
    highlighter = `<mark style="white-space:pre-wrap;background: linear-gradient(to bottom, transparent 50%%, #ffff00 50%%); padding: 0 4px; font-family: 'Arial', sans-serif; font-size: %s; color: #000; font-weight: 500;">%s</mark>`;

    // 代码块样式
    comment = `<code style="display:inline;white-space:pre-wrap;background: #f0f0f0; padding: 2px 6px; border-left: 4px solid #999; font-family: 'Monaco', 'Consolas', monospace; font-size: %s; color: #666; font-style: italic;">%s</code>`;

    // 错误提示样式
    error = `<code style="display:inline;white-space:pre-wrap;background: #fee; padding: 3px 8px; border-radius: 3px; border: 1px solid #fcc; font-family: 'Consolas', monospace; font-size: %s; color: #c00;">❌ %s</code>`;

    // 信息徽章样式
    badge = `<span style="display:inline;background: linear-gradient(135deg, #667eea 0%%, #764ba2 100%%); padding: 2px 8px; border-radius: 10px; font-family: -apple-system, sans-serif; font-size: %s; color: #fff; font-weight: 600; display: inline-block; box-shadow: 0 2px 4px rgba(0,0,0,0.2);">%s</span>`;

    // 代码块标题样式
    codeTitle = `<code style="display:inline;white-space:pre-wrap;background: #2d2d2d; padding: 4px 10px; border-top-left-radius: 6px; border-top-right-radius: 6px; font-family: 'Monaco', monospace; font-size: %s; color: #61dafb; border-bottom: 2px solid #61dafb;">📁 %s</code>`;

    // 赛博朋克风格 (Cyberpunk)
    cyberpunk = `<code style="display:inline;white-space:pre-wrap;background-color: #0d0221; border: 1px solid #00f3ff; color: #00f3ff; padding: 4px 10px; font-family: 'Consolas', monospace; font-size: %s; text-shadow: 2px 2px 0px #ff00ff; box-shadow: 3px 3px 0px #ff00ff; font-weight: bold; letter-spacing: 1px;">%s</code>`;

    // 新丑主义/波普风格 (Brutalism)
    brutalism = `<span style="display:inline;background-color: #ff90e8; border: 3px solid #000; color: #000; padding: 4px 8px; font-family: 'Arial Black', sans-serif; font-size: %s; font-weight: 900; box-shadow: 4px 4px 0px #000; transform: rotate(-1deg); display: inline-block;">%s</span>`;

    // 像素游戏风格 (8-Bit Pixel)
    pixel = `<code style="display:inline;white-space:pre-wrap;background-color: #2c2c2c; border: 4px solid #fff; outline: 4px solid #000; color: #39ff14; padding: 4px 8px; font-family: 'Courier New', monospace; font-size: %s; font-weight: bold; image-rendering: pixelated; margin: 4px;">%s</code>`;

    // 乐高积木 (Lego Style)
    lego = `<span style="display:inline;background: #e3000b; color: #fff; padding: 4px 10px; font-family: Arial, sans-serif; font-size: %s; font-weight: 900; border-top: 2px solid #ff4d4d; border-left: 2px solid #ff4d4d; border-right: 2px solid #990000; border-bottom: 2px solid #990000; text-shadow: 1px 1px 0 rgba(0,0,0,0.2);">%s</span>`;

    // 极简线框问 (Q)
    chatQ1 = `<span style="display:inline;background-color: #fff; color: #333; border: 1px solid #e0e0e0; border-left: 4px solid #4a90e2; padding: 8px 12px; border-radius: 4px; font-family: sans-serif; font-size: %s; display: inline-block;">🙋‍♂️ %s</span>`;

    // 极简线框答 (A)
    chatA1 = `<span style="display:inline;background-color: #f9f9f9; color: #555; border: 1px solid #e0e0e0; border-left: 4px solid #50e3c2; padding: 8px 12px; border-radius: 4px; font-family: sans-serif; font-size: %s; display: inline-block;">🤖 %s</span>`;

    // 引用块样式(左侧有线框,也就是 Mardown 里 `> 引用`的流行样式,需要支持微信公众号 )
    quote = `<blockquote style="display:block;white-space:normal;background: #f8f9fb; border-left: 4px solid #4299e1; padding: 12px 16px; border-radius: 0 8px 8px 0; color: #4a5568; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: %s; margin: 8px 0;">%s</blockquote>`;

}

/*
微信公众平台编辑器对内联 HTML 的限制比普通浏览器严格得多:
- 不建议为文章内容指定 font-family;
- 文字背景使用 gradient 在 Dark Mode 下会被转换为不可预测的纯色;
- !important、transform、backdrop-filter 等样式容易被编辑器覆盖或造成布局检测告警;
- inline 组件如果没有最大宽度,长文本在窄屏上可能溢出。

这里不试图伪造“官方清洗器”,只做一层保守的兼容处理。关闭“微信兼容输出”
后仍可复制原始样式,方便粘贴到其他富文本编辑器。
*/
var wechatGradientFallback = function(value){
    var v = string.lower(value);

    if(string.indexOf(v,"#0a0e27") || string.indexOf(v,"#1e1e1e")
        || string.indexOf(v,"#0d0221") || string.indexOf(v,"#000000")
        || string.indexOf(v,"#2c2c2c") || string.indexOf(v,"#2d2d2d")){
        return "#202124";
    }
    if(string.indexOf(v,"#ffd700") || string.indexOf(v,"#ffff00")) return "#fff59d";
    if(string.indexOf(v,"#84fab0")) return "#84fab0";
    if(string.indexOf(v,"#5e5ce6")) return "#4b49c6";
    if(string.indexOf(v,"#667eea")) return "#4c5fd5";
    if(string.indexOf(v,"#ff6b6b")) return "#c53b3b";

    return "#f5f5f5";
}

var wechatNormalizeStyle = function(styleText,forceBlock){
    var declarations = string.splitLiteral(styleText,";");
    var kept = [];
    var hasBackgroundColor = false;
    var hasLineHeight = false;
    var hasMaxWidth = false;
    var hasBoxSizing = false;
    var hasOverflowWrap = false;
    var hasDisplay = false;
    var hasWhiteSpace = false;
    var gradientFallback;

    for i,declaration in (declarations) {
        declaration = string.trim(declaration);
        if(declaration != ""){
            var colon = string.indexOf(declaration,":");
            if(colon){
                var name = string.lower(string.trim(string.slice(declaration,1,colon-1)));
                var value = string.trim(string.slice(declaration,colon+1));
                var cleanedValue = string.replaceLiteral(value,"!important","");
                value = string.trim(cleanedValue);
                var lowerValue = string.lower(value);
                var keep = true;

                if(name == "display" && hasDisplay) keep = false;
                if(name == "white-space" && hasWhiteSpace) keep = false;
                if(name == "display") hasDisplay = true;
                if(name == "white-space") hasWhiteSpace = true;

                if(name == "font-family" || name == "-webkit-font-family"){
                    keep = false;
                }
                elseif(name == "backdrop-filter" || name == "-webkit-backdrop-filter"){
                    keep = false;
                }
                elseif(name == "transform" || name == "-webkit-transform"){
                    keep = false;
                }
                elseif(name == "text-shadow"){
                    keep = false;
                }
                elseif((name == "background" || name == "background-image")
                    && string.indexOf(lowerValue,"gradient")){
                    keep = false;
                    if(!gradientFallback) gradientFallback = wechatGradientFallback(value);
                }
                elseif(name == "white-space"){
                    value = "normal";
                }
                elseif(name == "text-align" && lowerValue == "start"){
                    value = "left";
                }
                elseif(name == "text-align" && lowerValue == "end"){
                    value = "right";
                }
                elseif(name == "display"){
                    if(forceBlock) value = "block";
                    elseif(lowerValue == "inline") value = "inline-block";
                }
                elseif(name == "word-break" && lowerValue == "break-all"){
                    value = "break-word";
                }

                if(name == "background-color") hasBackgroundColor = true;
                if(name == "line-height") hasLineHeight = true;
                if(name == "max-width") hasMaxWidth = true;
                if(name == "box-sizing") hasBoxSizing = true;
                if(name == "overflow-wrap") hasOverflowWrap = true;

                if(keep) table.push(kept,name ++ ":" ++ value);
            }
        }
    }

    if(gradientFallback && !hasBackgroundColor)
        table.push(kept,"background-color:" ++ gradientFallback);
    if(!hasLineHeight) table.push(kept,"line-height:1.5");
    if(!hasMaxWidth) table.push(kept,"max-width:100%");
    if(!hasBoxSizing) table.push(kept,"box-sizing:border-box");
    if(!hasOverflowWrap) table.push(kept,"overflow-wrap:anywhere");

    return string.join(kept,";");
}

var wechatNormalizeHtml = function(html,forceBlock){
    if(!html) return html;

    return string.replace(html,`style="([^"]*)"`,function(styleText){
        return `style="` ++ wechatNormalizeStyle(styleText,forceBlock) ++ `"`;
    });
}

// 当前选中的样式
var currentStyle = "hotkey";
var rawHtml = "";
var currentHtml = "";

// 更新预览
import string.html;
updatePreview = function(){
    var text = winform.edit.text;
    if(!text || text == "") text = "示例文本";

    var fontSize = winform.tbFontSize.progressPos;
    fontSize = (1.5 /100 * fontSize + 0.5) + "em";

    var template = styles[currentStyle];

    var multiline = string.indexOf(text,'\r') || string.indexOf(text,'\n');
    text = string.html.fromText(text)
    rawHtml = string.format(template, fontSize, text);
    if(winform.checkWechat.checked)
        currentHtml = wechatNormalizeHtml(rawHtml,multiline);
    else
        currentHtml = rawHtml;



    var html =  `
<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <style>
        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
            padding: 20px;
            line-height: 1.6;
            color: #333;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            min-height: 90vh;
            margin: 0;
            background: linear-gradient(135deg, #f5f7fa 0%, #e4e8ee 100%);
            overflow-x: hidden; 
            overflow-y: auto; 
            height: 80%;
        }
        html {
            padding: 10px;
            background: linear-gradient(135deg, #f5f7fa 0%, #e4e8ee 100%);
        }
        pre {
            margin-top: 20px;
            background: #fff;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            box-shadow: 0 2px 8px rgba(0,0,0,0.08);
            border: 1px solid #e4e8ee;
        }
        blockquote {
            background: #f8f9fb;
            border-left: 4px solid #4299e1;
            padding: 12px 16px;
            margin: 20px 0;
            border-radius: 0 8px 8px 0;
            color: #4a5568;
        }
        blockquote ol {
            margin: 0;
            padding-left: 20px;
        }
        blockquote li {
            margin: 4px 0;
        }
        `+ $"~\docs\style.css"  +`
    </style> 
    <script>`+$"~\docs\index.js"+`

Prism.languages.markup={comment:/<!--[\w\W]*?-->/,prolog:/<\?[\w\W]+?\?>/,doctype:/<!DOCTYPE[\w\W]+?>/,cdata:/<!\[CDATA\[[\w\W]*?]]>/i,tag:{pattern:/<\/?(?!\d)[^\s>\/=.$<]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\\1|\\?(?!\1)[\w\W])*\1|[^\s'">=]+))?)*\s*\/?>/i,inside:{tag:{pattern:/^<\/?[^\s>\/]+/i,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"attr-value":{pattern:/=(?:('|")[\w\W]*?(\1)|[^\s>]+)/i,inside:{punctuation:/[=>"']/}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:/&#?[\da-z]{1,8};/i},Prism.hooks.add("wrap",function(a){"entity"===a.type&&(a.attributes.title=a.content.replace(/&amp;/,"&"))}),Prism.languages.xml=Prism.languages.markup,Prism.languages.html=Prism.languages.markup,Prism.languages.mathml=Prism.languages.markup,Prism.languages.svg=Prism.languages.markup;
</script>
</head>
<body>
<div style="background: #fff; padding: 30px 50px; border-radius: 12px; box-shadow: 0 4px 20px rgba(0,0,0,0.08);">
`+currentHtml+`
</div>
<div style="width: 100%; overflow: hidden; margin-top:20px;">
<pre style="white-space: pre-wrap; word-wrap: break-word; overflow-wrap: break-word; max-width: 100%%;">
<code style="display:block;white-space:pre-wrap;white-space: inherit; word-break: break-all; display: block;" class="html language-html">
`+string.html.escape(currentHtml)+`
</code></pre>

<blockquote id="info">
<ol>
<li>请在左侧点选样式,方向键快速切换,回车快速复制
` +(winform.checkWechat.checked?"<li>为兼容公众号新规,不再使用渐变、阴影、3D 变形等视觉效果":"")+`
<li>建议粘贴于 2 个空格中间
</ol>
</blockquote>
</div>
</body></html>` 

    wb.html = html;
}

import win.debounce;
updatePreview = win.debounce(updatePreview,500);

// 单选框事件 - 第一列
winform.radioHotkey.oncommand = function(id,event){
    currentStyle = "hotkey";
    updatePreview();
}

winform.radioGitHub.oncommand = function(id,event){
    currentStyle = "github";
    updatePreview();
}

winform.radioVSCode.oncommand = function(id,event){
    currentStyle = "vscode";
    updatePreview();
}

winform.radioStackOverflow.oncommand = function(id,event){
    currentStyle = "stackoverflow";
    updatePreview();
}

winform.radioMedium.oncommand = function(id,event){
    currentStyle = "medium";
    updatePreview();
}

winform.radioGradient.oncommand = function(id,event){
    currentStyle = "gradient";
    updatePreview();
}

// 单选框事件 - 第二列
winform.radioNeon.oncommand = function(id,event){
    currentStyle = "neon";
    updatePreview();
}

winform.radioGlass.oncommand = function(id,event){
    currentStyle = "glass";
    updatePreview();
}

winform.radioNeumorphism.oncommand = function(id,event){
    currentStyle = "neumorphism";
    updatePreview();
}

winform.radioRainbow.oncommand = function(id,event){
    currentStyle = "rainbow";
    updatePreview();
}

winform.radioTerminal.oncommand = function(id,event){
    currentStyle = "terminal";
    updatePreview();
}

winform.radioMacTag.oncommand = function(id,event){
    currentStyle = "macTag";
    updatePreview();
}

// 单选框事件 - 第三列和第四列
winform.radioWarning.oncommand = function(id,event){
    currentStyle = "warning";
    updatePreview();
}

winform.radioSuccess.oncommand = function(id,event){
    currentStyle = "success";
    updatePreview();
}

winform.radio3D.oncommand = function(id,event){
    currentStyle = "three3d";
    updatePreview();
}

winform.radioTypewriter.oncommand = function(id,event){
    currentStyle = "typewriter";
    updatePreview();
}

winform.radioHighlighter.oncommand = function(id,event){
    currentStyle = "highlighter";
    updatePreview();
}

winform.radioComment.oncommand = function(id,event){
    currentStyle = "comment";
    updatePreview();
}

winform.radioError.oncommand = function(id,event){
    currentStyle = "error";
    updatePreview();
}

winform.radioBadge.oncommand = function(id,event){
    currentStyle = "badge";
    updatePreview();
}

winform.radioCodeTitle.oncommand = function(id,event){
    currentStyle = "codeTitle";
    updatePreview();
}


winform.radioCyberpunk.oncommand = function(id,event){
    currentStyle = "cyberpunk";
    updatePreview();    
}

winform.radioBrutalism.oncommand = function(id,event){
    currentStyle = "brutalism";
    updatePreview();    
}


winform.radioPixel.oncommand = function(id,event){
    currentStyle = "pixel";
    updatePreview();    
}

winform.radioLego.oncommand = function(id,event){
    currentStyle = "lego";
    updatePreview();    
}

winform.radioChatQ1.oncommand = function(id,event){
    currentStyle = "chatQ1";
    updatePreview();    
}

winform.radioChatA1.oncommand = function(id,event){
    currentStyle = "chatA1";
    updatePreview();    
}

winform.radioQuote.oncommand = function(id,event){
    currentStyle = "quote";
    updatePreview();    
}

// 编辑框文本改变事件
winform.edit.oncommand = function(id,event){
    updatePreview();
}

// 微信兼容输出开关
winform.checkWechat.oncommand = function(id,event){
    updatePreview();
}

// 复制按钮
winform.btnCopy.oncommand = function(id,event){
    winform.btnCopy.disabledText = ["✶","✸","✹","✺","✹","✷"]

    import win.clip.html;
    var cbHtml = win.clip.html();
    cbHtml.write(currentHtml);

    // 同时提供纯文本回退格式;支持 HTML 的编辑器仍会优先使用 CF_HTML。
    var plainText = string.html.toText(currentHtml);
    if(plainText) win.clip.write(plainText,false);

    // 彩色 emoji 动画效果
    var frames = {
        "📋 快好了...",
        "📋✨ 快好了....",
        "📋✨✨✨✨ 快好了...",
        "📋✨✨✨✨✨✨✨✨ 快好了..."
    };

    for(i=1;#frames){
        wb.getEle("info").innerText = frames[i];
        thread.delay(i < 4 ? 100 : 150); // 前面快一点,后面慢一点
    }


    if(winform.checkWechat.checked)
        wb.getEle("info").innerText = "✅ 已复制微信兼容 HTML!请在微信公众号编辑器中直接粘贴。";
    else
        wb.getEle("info").innerText = "✅ 已复制原始 HTML!请在支持 HTML 的富文本编辑器中直接粘贴。";

    winform.btnCopy.disabledText = null;
}

winform.onOk = winform.btnCopy.oncommand;

// 链接点击事件
winform.lnkCodeBlock.onHyperlinkClick = function(nmSysLink,url,id,index){
    import ide;
    ide.createProcess("~/examples/WebUI/web.view/OtherApps/prism.aardio");
}

winform.checkWechat.skin({
    color={
        default=0xFFFFFFFF;
        hover=0xFFFFF3CC;
        active=0xFFFFDF80;
        disabled=0xFFB8C9DB
    };
    checked={
        iconText='\uF14A';
        color={
            default=0xFFFFE8A3;
            hover=0xFFFFF3CC;
            active=0xFFFFD966;
            disabled=0xFFB8C9DB
        }
    }
})

// 滑尺设置
winform.tbFontSize.setTrackbarRange(1,100);
winform.tbFontSize.progressPos = 27;
winform.tbFontSize.onPosChanged = function( pos,triggeredByUser ){
    if(triggeredByUser){
        updatePreview();
    }
}
winform.tbFontSize.skin({
    background={
        default=0xFFD9904A  // 蓝色轨道背景
    };
    foreground={
        default=0xFFEECF5B; // 浅蓝色进度
        hover=0xFFFFE066    // 悬停更亮
    };
    color={
        default=0xFFFFFFFF; // 白色滑块
        hover=0xFFF0F0F0
    }
})

updatePreview();

winform.show();
win.loopMessage();
Markdown 格式