@codady/coax 0.0.1 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/coax.cjs.js +829 -140
- package/dist/coax.cjs.min.js +3 -3
- package/dist/coax.esm.js +823 -140
- package/dist/coax.esm.min.js +3 -3
- package/dist/coax.umd.js +849 -138
- package/dist/coax.umd.min.js +3 -3
- package/examples/.htaccess +0 -0
- package/examples/append-highlight.html +82 -0
- package/examples/color-selector.html +412 -0
- package/examples/css-highlight.html +2 -18
- package/examples/deepseek-highlight.html +91 -0
- package/examples/js-highlight.html +2 -17
- package/examples/md-highlight.html +60 -0
- package/examples/nginx.htaccess +0 -0
- package/examples/plain-highlight.html +47 -0
- package/examples/replace-highlight.html +69 -0
- package/examples/stream-highlight.html +64 -0
- package/examples/theme-highlight.html +69 -0
- package/package.json +19 -3
- package/rollup.config.js +3 -3
- package/src/Coax.js +50 -184
- package/src/Coax.ts +56 -207
- package/src/components/CoaxElem.js +457 -0
- package/src/components/CoaxElem.ts +488 -0
- package/src/modules.js +12 -0
- package/src/modules.ts +23 -0
- package/src/rules/css.js +11 -0
- package/src/rules/css.ts +11 -0
- package/src/rules/html.js +13 -0
- package/src/rules/html.ts +13 -0
- package/src/rules/javascript.js +10 -0
- package/src/rules/javascript.ts +10 -0
- package/src/rules/markdown.js +29 -0
- package/src/rules/markdown.ts +41 -0
- package/src/rules/ruleCss - /345/211/257/346/234/254.js" +10 -0
- package/src/rules/ruleHTML - /345/211/257/346/234/254.js" +12 -0
- package/src/rules/ruleJs - /345/211/257/346/234/254.js" +10 -0
- package/src/rules/ruleTs - /345/211/257/346/234/254.js" +12 -0
- package/src/rules/typescript.js +12 -0
- package/src/rules/typescript.ts +12 -0
- package/src/tools/copy.js +26 -0
- package/src/tools/copy.ts +29 -0
- package/tsconfig.json +2 -2
package/dist/coax.umd.min.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @since Last modified: 2026-1-
|
|
2
|
+
* @since Last modified: 2026-1-12 9:47:5
|
|
3
3
|
* @name Coax event management system.
|
|
4
|
-
* @version 0.0.
|
|
4
|
+
* @version 0.0.3
|
|
5
5
|
* @author AXUI development team <3217728223@qq.com>
|
|
6
6
|
* @description Coax is a custom web component that enables syntax highlighting for various programming languages inside your HTML documents.
|
|
7
7
|
* @see {@link https://coax.axui.cn|Official website}
|
|
@@ -12,4 +12,4 @@
|
|
|
12
12
|
* @copyright This software supports the MIT License, allowing free learning and commercial use, but please retain the terms 'coax', 'Coax' and 'COAX' within the software.
|
|
13
13
|
* @license MIT license
|
|
14
14
|
*/
|
|
15
|
-
!function(e){"function"==typeof define&&define.amd?define(e):e()}(function(){"use strict";class Coax extends HTMLElement{static languages=new Map;rawCode;constructor(){super(),this.attachShadow({mode:"open"}),this.rawCode=this.textContent?.replace(/^\s*\n|\n\s*$/g,"")||""}static register(e,{rules:n,theme:t={},internalCss:a="",cssPrefix:r=""}){this.languages.set(e,{rules:n,theme:t,internalCss:a,cssPrefix:r}),document.querySelectorAll("ax-code").forEach(n=>{n.getAttribute("lang")===e&&n.render()})}connectedCallback(){this.render()}static get observedAttributes(){return["lang","height","max-height"]}attributeChangedCallback(){this.render()}render(){const e=this.getAttribute("lang")||"js",n=Coax.languages.get(e),t=n?.cssPrefix||e,a=this.getAttribute("height"),r=this.getAttribute("max-height");let s="",o="";if(n){const e=new RegExp(n.rules.map(e=>`(${e.reg.source})`).join("|"),"g");s=this.rawCode.replace(/[&<>]/g,e=>({"&":"&","<":"<",">":">"}[e])).replace(e,(e,...a)=>{const r=a.findIndex(e=>void 0!==e);return-1!==r&&n.rules[r]?`<span class="ax-${t}-${n.rules[r].name}">${e}</span>`:e}),o=n.rules.map(e=>`\n .ax-${t}-${e.name} { color: var(--ax-${t}-${e.name}); }\n `).join("\n")}else s=this.rawCode;const i=n?.theme?Object.entries(n.theme).map(([e,n])=>`--ax-${t}-${e}: ${n};`).join("\n"):"";this.shadowRoot.innerHTML=`\n <style>\n :host { \n ${i} \n\n font-size: var(--ax-code-fs,14px);\n display: block; \n padding: var(--ax-code-p,1em);\n box-sizing:border-box;\n line-height: var(--ax-code-lh,1.5);\n background-color:var(--ax-code-bg,rgba(0,0,0,0.02));\n color:var(--ax-code-c,#333);\n border:var(--ax-code-bw,1px) solid var(--ax-code-bc,rgba(0,0,0,0.08));\n height:${a||"var(--ax-code-h,auto)"};\n max-height:${r||"var(--ax-code-mh,500px)"};\n overflow:auto;\n transition: border-color 0.3s ease,color 0.3s ease; \n border-radius: var(--ax-code-r,9px);\n }\n pre,code{\n font-family:"Consolas", "Monaco", "Andale Mono", "Ubuntu Mono", "monospace", "microsoft yahei", "Microsoft JhengHei", "Yu Mincho", "simsun";\n margin:0;\n padding:0;\n }\n \n \n \n ${o}\n \n \n ${n?.internalCss||""}\n </style>\n <pre><code>${s}</code></pre>`}}customElements.define("ax-code",Coax),Coax.register("html",{rules:[{name:"comment",reg:/<!--[\s\S]*?-->/},{name:"doctype",reg:/<!DOCTYPE[\s\S]*?>/i},{name:"tag",reg:/<\/?[a-zA-Z0-9]+/},{name:"attr",reg:/[a-zA-Z-]+(?=\s*=\s*)/},{name:"string",reg:/(['"])(?:\\.|[^\\])*?\1/},{name:"bracket",reg:/\/?>/}]}),Coax.register("css",{rules:[{name:"comment",reg:/\/\*[\s\S]*?\*\//},{name:"value",reg:/(?:'|")(?:\\.|[^\\'"\b])*?(?:'|")/},{name:"func",reg:/[a-z-]+\(?=/},{name:"property",reg:/[a-z-]+(?=\s*:)/},{name:"selector",reg:/[.#a-z0-9, \n\t>:+()_-]+(?=\s*\{)/i},{name:"unit",reg:/(?<=\d)(px|em|rem|%|vh|vw|ms|s|deg)/},{name:"number",reg:/\b\d+(\.\d+)?\b/},{name:"punct",reg:/[{}();:]/}],theme:{type:"#61afef",keyword:"#d19a66",string:"#98c379",op:"#abb2bf"},internalCss:"\n .ax-css-string { color: var(--ax-code-string); }\n .ax-css-string::first-letter { color: var(--ax-code-c); }\n "}),Coax.register("js",{rules:[{name:"comment",reg:/\/\/[^\n]*|\/\*[\s\S]*?\*\//},{name:"string",reg:/(?:'|"|`)(?:\\.|[^\\'"\b])*?(?:'|"|`)/},{name:"keyword",reg:/\b(async|await|break|case|catch|class|const|continue|default|delete|do|else|export|extends|finally|for|function|if|import|in|instanceof|new|return|super|switch|this|throw|try|typeof|var|while|with|yield|let|static)\b/},{name:"builtin",reg:/\b(console|window|document|Math|JSON|true|false|null|undefined|Object|Array|Promise)\b/},{name:"number",reg:/\b\d+\b/},{name:"func",reg:/\b[a-zA-Z_]\w*(?=\s*\()/},{name:"op",reg:/[+\-*/%=<>!&|^~]+/}]}),Coax.register("ts",{rules:[{name:"comment",reg:/\/\/[^\n]*|\/\*[\s\S]*?\*\//},{name:"string",reg:/(?:'|"|`)(?:\\.|[^\\'"\b])*?(?:'|"|`)/},{name:"decorator",reg:/@[a-zA-Z_]\w*/},{name:"keyword",reg:/\b(abstract|as|async|await|break|case|catch|class|const|continue|debugger|declare|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|is|keyof|let|module|namespace|new|package|private|protected|public|readonly|return|set|static|super|switch|this|throw|try|type|typeof|var|while|with|yield)\b/},{name:"builtin",reg:/\b(any|boolean|never|number|string|symbol|unknown|void|undefined|null|boolean|true|false|console|window|document)\b/},{name:"type",reg:/\b[A-Z]\w*\b/},{name:"number",reg:/\b\d+\b/},{name:"func",reg:/\b[a-zA-Z_]\w*(?=\s*\()/},{name:"op",reg:/(\?\.|![:\.]|[+\-*/%=<>!&|^~]+)/}]})});
|
|
15
|
+
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).coax=t()}(this,function(){"use strict";const e="ax",typeWriter=(e,t)=>{const n=t.speed||100;return new Promise(i=>{t?.onBeforeType?.(e);let r=0;const o=setInterval(()=>{if(r<e.length){const n=e.charAt(r),i=e.substring(0,r+1);t?.onDuringType?.(n,i),r++}else clearInterval(o),i(e),t?.onAfterType?.(e)},n)})},trim$1=(e,t="compress")=>{if("string"!=typeof e)return"";switch(t){case"start":return e.trimStart();case"end":return e.trimEnd();case"both":return e.trim();case"global":return e.replace(/[\s\r\n]+/g,"");default:return e.trim().replace(/[\s\r\n]+/g," ")}},parseClasses$1=e=>{let t,n=[];return Array.isArray(e)?n=e.filter(e=>e&&"string"==typeof e):(t=(e=trim$1(e)).includes(",")?",":" ",n=e.split(t)),n.map(e=>trim$1(e,"global")).filter(Boolean)},getDataType=e=>{let t,n=Object.prototype.toString.call(e).slice(8,-1);return t="Function"===n&&/^\s*class\s+/.test(e.toString())?"Class":"Object"===n&&Object.getPrototypeOf(e)!==Object.prototype?"Instance":n,t},getEl=(e,t=document.body)=>{let n=getDataType(e),i=getDataType(t),r=i.includes("HTML")||"ShadowRoot"===i?t:document.querySelector(t),o=r&&r instanceof HTMLTemplateElement?r.content:r,a=null;if(e)if(n.includes("HTML"))a=e;else if("String"===n)try{a=(o||document).querySelector(e.trim())}catch{a=null}return a},createEl=(e,t,n)=>{let i=(e=e||"div").toUpperCase().trim(),r=document.createElement(i),o=getDataType(t);if(t&&"Object"===o)for(let e in t)t.hasOwnProperty(e)&&r.setAttribute(e,"string"==typeof t[e]?t[e]:JSON.stringify(t[e]));return((e,t)=>{if(""===t||null==t)return!1;let n=getDataType(t);if("TEMPLATE"===i)e.innerHTML=t.toString();else if("Array"===n&&t.length>0)for(let n of t){if(getDataType(n).includes("HTML"))e.appendChild(n);else{let t=createEl(n.name,n.attrs,n.content);t&&e.appendChild(t)}}else if(n.includes("HTML"))e.appendChild(t);else if("String"===n&&t.trim().startsWith("#")&&t.trim().length>1){let n=getEl(t);if(!n)return;"TEMPLATE"===n.nodeName?e.appendChild(n.content.cloneNode(!0)):e.insertAdjacentHTML("beforeEnd",n.innerHTML)}else e.insertAdjacentHTML("beforeEnd",t)})(r,n),r},isEmpty=e=>{let t,n=getDataType(e);return t=!e||("Object"===n?0===Object.keys(e).length:"Array"===n?""===e.join(""):"Function"===n?"{}"===e.toString().replace(/\s+/g,"").match(/{.*}/g)[0]:"Symbol"===n?"()"===e.toString().replace(/\s+/g,"").match(/\(.*\)/g)[0]:"Set"===n||"Map"===n?0===e.size:"Date"===n?isNaN(e.getTime()):"RegExp"===n?""===e.source:"ArrayBuffer"===n?0===e.byteLength:"NodeList"===n||"HTMLCollection"===n||"length"in e&&"number"==typeof e.length?0===e.length:"size"in e&&"number"==typeof e.size?0===e.size:"Error"===n||e instanceof Error?""===e.message:!(!n.includes("Array")||!["Uint8Array","Int8Array","Uint16Array","Int16Array","Uint32Array","Int32Array","Float32Array","Float64Array"].includes(n))&&0===e.length),t},t="rep",createTools=n=>{const i=createEl("span",{class:`${e}-box-tools`}),renderFn=e=>{const n={},i=e.extendable?`<i ${t}="arrow"></i>`:"",r=(e.icon?`<i ${t}="icon">${e.icon}</i>`:"")+(e.disk?`<i ${t}="disk"><img src="${e.disk}"/></i>`:"")+(e.cube?`<i ${t}="cube"><img src="${e.cube}"/></i>`:"")+(e.image?`<i ${t}="image"><img src="${e.image}"/></i>`:"")+(e.label?`<i ${t}="label">${e.label}</i>`:"")+i;e.title&&(n.title=e.title),e.focusable&&(n.tabindex=1),e.wrapEl=createEl(e.nodeName||"span",Object.assign(n,e.attrs),r),e.iconEl=e.wrapEl.querySelector(`[${t}="icon"]`),e.cubeEl=e.wrapEl.querySelector(`[${t}="cube"]`),e.diskEl=e.wrapEl.querySelector(`[${t}="disk"]`),e.imageEl=e.wrapEl.querySelector(`[${t}="image"]`),e.labelEl=e.wrapEl.querySelector(`[${t}="label"]`),!isEmpty(e.classes)&&((e,t)=>{const n=getEl(e),i=parseClasses$1(t);n&&0!==i.length&&i.forEach(e=>{n.classList.add(e)})})(e.wrapEl,e.classes),!isEmpty(e.styles)&&(e.wrapEl.style.cssText+=e.styles)};for(let e of n)renderFn(e),i.appendChild(e.wrapEl),e?.action?.(e);return i};class CoaxElem extends HTMLElement{static languages=new Map;static tools=[];source;_renderQueued=!1;baseStylesEl;themeStylesEl;dynamicStylesEl;highlightedCodeEl;headerEl;codeNameEl;codeToolsEl;codeBodyEl;alias;lineString;speed;autoScroll;constructor(){super(),this.attachShadow({mode:"open"}),this.source=this.textContent?.replace(/^\s*\n|\n\s*$/g,"")||"",this.lang="plain",this.alias="Plain Text",this.lineString="",this.speed=5,this.autoScroll=!0,this.shadowRoot.innerHTML=`\n <style id="base-styles">\n :host { \n --border-width:1px;\n --border-style:solid;\n --radius:9px;\n --height:auto;\n --max-height:500px;\n --radius:9px;\n --padding:1em;\n --font-size:16px;\n --line-height:1.8;\n --background:rgb(247, 247, 247);\n --border-color:rgb(224, 224, 224);\n --color-code:rgb(51, 51, 51);\n --color-index:rgb(153, 153, 153);\n --color-stripe:rgba(0,0,0,0.04);\n --color-hover:rgba(0,0,0,0.06);\n } \n :host([scheme="dark"]){\n --background: #282c34;\n --border-color: transparent;\n --color-code: #abb2bf;\n --color-index:rgb(153, 153, 153);\n --color-stripe:rgba(255,255,255,0.04);\n --color-hover:rgba(255,255,255,0.06);\n }\n @media (prefers-color-scheme: dark) {\n :host{\n --background: #282c34;\n --border-color: transparent;\n --color-code: #abb2bf;\n --color-index:rgb(153, 153, 153);\n --color-stripe:rgba(255,255,255,0.04);\n --color-hover:rgba(255,255,255,0.06);\n }\n }\n :host {\n font-size: var(--${e}-code-font-size,var(--font-size));\n display: block; \n box-sizing:border-box;\n background:var(--${e}-code-background-color,var(--background));\n color:var(--${e}-code-color,var(--color-code));\n border:var(--${e}-code-border-width,var(--border-width)) var(--${e}-code-border-style,var(--border-style)) var(--${e}-code-border-color,var(--border-color));\n transition: border-color 0.3s ease,color 0.3s ease; \n border-radius: var(--${e}-code-radius,var(--radius));\n }\n #code-header{\n line-height:calc(var(--${e}-code-line-height,var(--line-height))*1.5);\n padding-inline-start:var(--${e}-code-padding,var(--padding));\n display:flex;\n \n >:first-child{\n flex:auto;\n }\n }\n #code-body{\n padding: var(--${e}-code-padding,var(--padding)) 0;\n height:var(--${e}-code-height,var(--height));\n max-height:var(--${e}-code-max-height,var(--max-height));\n overflow:auto;\n }\n pre,code{\n font-family:"Consolas", "Monaco", "Andale Mono", "Ubuntu Mono", "monospace";\n margin:0; padding:0;\n }\n code>div{\n display:flex;\n padding:0 var(--${e}-code-padding,var(--padding));\n line-height: var(--${e}-code-line-height,var(--line-height));\n box-sizing:border-box;\n \n >div{\n flex:auto;\n }\n }\n code>div>div:empty:before{\n content:' ';\n }\n :host([indexed]) code>div:before{\n display:inline-flex;\n color:var(--color-index);\n content: attr(data-index);\n min-width:var(--${e}-code-index-width,2em);\n margin-inline-end:var(--${e}-code-padding,8px);\n }\n :host([striped]) code>div:nth-child(odd){\n background-color:var(--color-stripe);\n }\n :host([hoverable]) code>div:hover{\n background-color:var(--color-hover);\n }\n :host([wrapped]) code>div>div{\n white-space: pre-wrap;\n }\n :host([unnamed]) #code-name{\n display:none;\n }\n .${e}-box-tools{\n >*{\n font-size:14px;\n display:inline-flex;\n align-items:center;\n justify-content:center;\n height:2em;\n line-height:2em;\n aspect-ratio:1/1;\n margin-inline-end:8px;\n transition:all 200ms ease;\n border-radius:6px;\n &:hover{\n cursor:pointer;\n background-color:rgba(0,0,0,.04);\n }\n }\n [rep=icon]{\n display:inline-flex;\n align-items:center;\n justify-content:center;\n }\n }\n [disabled]{\n pointer-event:none;\n }\n </style>\n <style id="dynamic-styles"></style>\n <style id="theme-styles"></style>\n <div id="code-header"><span id="code-name">${this.alias}</span><div id="code-tools"></div></div>\n <div id="code-body">\n <pre><code id="highlight-code"></code></pre>\n </div>\n `,this.baseStylesEl=getEl("#base-styles",this.shadowRoot),this.themeStylesEl=getEl("#theme-styles",this.shadowRoot),this.dynamicStylesEl=getEl("#dynamic-styles",this.shadowRoot),this.headerEl=getEl("#code-header",this.shadowRoot),this.codeNameEl=getEl("#code-name",this.shadowRoot),this.codeToolsEl=getEl("#code-tools",this.shadowRoot),this.codeBodyEl=getEl("#code-body",this.shadowRoot),this.highlightedCodeEl=getEl("#highlight-code",this.shadowRoot),this.codeBodyEl.addEventListener("scroll",()=>{let e=this.codeBodyEl.scrollTop+this.codeBodyEl.clientHeight<this.codeBodyEl.scrollHeight;this.autoScroll=!e})}static register(e,t){this.languages.set(e,{...t})}static addTools(e){CoaxElem.tools=e}mountTools(e){requestAnimationFrame(()=>{this.codeToolsEl.innerHTML="";let t=e.map(e=>(e.action=e.action.bind(this),e));this.codeToolsEl.appendChild(createTools(t))})}connectedCallback(){this.render()}static get observedAttributes(){return["lang","height","max-height","tools","speed"]}attributeChangedCallback(e,t,n){if(t!==n&&("height"!==e&&"max-height"!==e||this.updateStyleByRegExp(e,n),"speed"===e&&(this.speed=~~!!n),"lang"===e&&(this.lang=n,this.render()),"tools"===e)){n||(this.codeToolsEl.innerHTML="");const e=parseClasses$1(n),t=CoaxElem.tools.filter(t=>e.includes(t.name));if(!t.length)return;this.mountTools(t)}}updateStyleByRegExp(e,t){const n=new RegExp(`;\\n\\s*${e}:\\s*[^;]+;`,"g");this.baseStylesEl.textContent=this.baseStylesEl.textContent.replace(n,`;\n${e}: ${t};`)}getCssPrefix(e){return(e?.cssPrefix||this.lang).replace(/[^a-zA-Z0-9_-]/g,"\\$&")}getHighLightString(t,n){if(!(n=n||CoaxElem.languages.get(this.lang)))return t;const i=this.getCssPrefix(n),r=new RegExp(n.rules.map(e=>`(${e.pattern.source})`).join("|"),"g");return t.replace(r,(t,...r)=>{const o=r.findIndex(e=>void 0!==e);return-1!==o&&n.rules[o]?`<span class="${e}-${i}-${n.rules[o].token}">${t}</span>`:t})}createLineWrap(e,t){let n=0;if(null==e&&null==t)n=this.highlightedCodeEl.children.length;else{n=(t||this.highlightedCodeEl.children.length)+e}return createEl("div",{"data-index":n},"<div></div>")}getLineToFill(e,t,n){n=n||CoaxElem.languages.get(this.lang);let i=this.getHighLightString(t,n);e.innerHTML=i}async highlight(e){const t=CoaxElem.languages.get(this.lang),n=this.highlightedCodeEl.children.length,i=e?e.split("\n"):[];if(this.updateName(t),!i.length)return!0;for(let[e,r]of i.entries()){if(!r.trim()&&this.hasAttribute("sanitized"))continue;const i=this.createLineWrap(e,n),o=i.lastElementChild;this.closeLine(i),this.hasAttribute("speed")?(this.highlightedCodeEl.appendChild(i),await typeWriter(r,{speed:this.speed,onDuringType:(e,t)=>{o.innerHTML=t}}),this.getLineToFill(o,r,t)):(this.getLineToFill(o,r,t),this.highlightedCodeEl.appendChild(i))}return this.autoScrollCode(),!0}autoScrollCode(){this.autoScroll&&(this.codeBodyEl.scrollTop=this.codeBodyEl.scrollHeight)}injectThemeStyles(){const t=CoaxElem.languages.get(this.lang);if(!t)return;let n=this.getCssPrefix(t),i=t.rules.map(t=>`\n .${e}-${n}-${t.token} { color: var(--${e}-${n}-${t.token}${t.light?","+t.light:""});}`).join("\n"),r="",o="";r+=':host([scheme="dark"]){',r+=t.rules.map(t=>"\n "+(t.light?`\n .${e}-${n}-${t.token} {color: var(--${e}-${n}-${t.token},${t.dark});}`:"")).join("\n"),r+="}",o="@media (prefers-color-scheme: dark){\n :host{\n ",o+=t.rules.map(t=>`\n ${t.light?`\n .${e}-${n}-${t.token} { color: var(--${e}-${n}-${t.token},${t.dark}); }`:""} `).join("\n"),o+="}",this.dynamicStylesEl.textContent=i+r+o,t?.themeStyles&&(this.themeStylesEl.textContent=t.themeStyles)}updateName(e){this.hasAttribute("unnamed")||(e?(this.alias=e.alias||this.lang,this.codeNameEl.innerHTML=this.alias):this.codeNameEl.innerHTML="Plain Text")}render(e=this.source){this._renderQueued||(this._renderQueued=!0,requestAnimationFrame(async()=>{this.clear(),this.injectThemeStyles(),await this.highlight(e),this._renderQueued=!1}))}clear(){this.highlightedCodeEl.innerHTML=this.source=this.lineString=""}async replace(e){this.clear(),await this.highlight(e)}async append(e){this.source+=`\n${e}`,await this.highlight(e)}getActiveCodeWrap(){const e=this.highlightedCodeEl.lastElementChild,t=!e||this.highlightedCodeEl.lastElementChild?.completed?this.createLineWrap():e;return{lineWrap:t,codeWrap:t.lastElementChild}}closeLine(e){(e=e||this.highlightedCodeEl.lastElementChild)&&(e.completed=!0)}openLine(e){(e=e||this.highlightedCodeEl.lastElementChild)&&(e.completed=!1)}stream(e,t=!1){const{lineWrap:n,codeWrap:i}=this.getActiveCodeWrap();this.highlightedCodeEl.appendChild(n),this.source+=e,t&&this.closeLine(n),e.startsWith("\n")||e.startsWith("\r")?(this.closeLine(n),this.getLineToFill(i,this.lineString),this.lineString=""):(i.innerHTML+=e,this.lineString+=e),this.autoScrollCode()}}const trim=(e,t="")=>{if("string"!=typeof e)return"";switch(t){case"start":return e.trimStart();case"end":return e.trimEnd();case"both":return e.trim();case"global":return e.replace(/[\s\r\n]+/g,"");default:return e.trim().replace(/[\s\r\n]+/g," ")}},wrap=(e,t,n=!1,i)=>{const r=i?.size||"1em",o=i?.color||"currentColor",a=i?.thickness||2,l=i?.classes?(e=>{let t,n=[];return Array.isArray(e)?n=e.filter(e=>e&&"string"==typeof e):(t=(e=trim(e)).includes(",")?",":" ",n=e.split(t)),n.map(e=>trim(e,"global")).filter(Boolean)})(i.classes).join(" "):"",s=t.name.replace(/([A-Z])/g,"-$1").toLowerCase();return`<svg xmlns="http://www.w3.org/2000/svg" width="${r}" height="${r}" viewBox="0 0 24 24" fill="none" stroke="${o}"\n stroke-width="${a}" stroke-linecap="round" stroke-linejoin="round" class="${s} ${l}">\n ${n?((e="")=>`\n <style>\n :where([dir="rtl"]) .icax-${e},\n :where(:dir(rtl)) .icax-${e} {\n transform: scaleX(-1);\n transform-origin: center;\n }\n </style>\n`)(s.split("-")[1]):""}\n ${e}\n </svg>`},icaxCheck=e=>wrap('<polyline points="20 6 9 17 4 12"></polyline>',icaxCheck,!1,e),icaxCopy=e=>wrap('<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>',icaxCopy,!1,e),n={name:"copy",icon:icaxCopy(),action:function(e){e.wrapEl.onclick=()=>{navigator.clipboard.writeText(this.source).then(()=>{e.iconEl.innerHTML=icaxCheck(),e.iconEl.toggleAttribute("disabled",!0),setTimeout(()=>{e.iconEl.removeAttribute("disabled"),e.iconEl.innerHTML=icaxCopy()},2e3)}).catch(e=>{})}}},i=CoaxElem;return i.register("css",{alias:"CSS",rules:[{token:"comment",pattern:/\/\*[\s\S]*?\*\//,light:"#6a737d",dark:"#8b949e"},{token:"value",pattern:/(?:'|")(?:\\.|[^\\'"\b])*?(?:'|")/,light:"#032f62",dark:"#a5d6ff"},{token:"func",pattern:/[a-z-]+\(?=/,light:"#e36209",dark:"#ffa657"},{token:"property",pattern:/[a-z-]+(?=\s*:)/,light:"#005cc5",dark:"#79c0ff"},{token:"selector",pattern:/[.#a-z0-9, \n\t>:+()_-]+(?=\s*\{)/i,light:"#22863a",dark:"#7ee787"},{token:"unit",pattern:/(?<=\d)(px|em|rem|%|vh|vw|ms|s|deg)/,light:"#d73a49",dark:"#ff7b72"},{token:"number",pattern:/\b\d+(\.\d+)?\b/,light:"#005cc5",dark:"#79c0ff"},{token:"punct",pattern:/[{}();:]/,light:"#24292e",dark:"#c9d1d9"}]}),i.register("html",{alias:"HTML",rules:[{token:"comment",pattern:/<!--[\s\S]*?-->/,light:"#999999",dark:"#6e7681"},{token:"doctype",pattern:/<!DOCTYPE[\s\S]*?>/i,light:"#6a737d",dark:"#8b949e"},{token:"tag",pattern:/<\/?[a-zA-Z0-9]+/,light:"#22863a",dark:"#7ee787"},{token:"attr",pattern:/[a-zA-Z-]+(?=\s*=\s*)/,light:"#6f42c1",dark:"#d2a8ff"},{token:"string",pattern:/(['"])(?:\\.|[^\\])*?\1/,light:"#032f62",dark:"#a5d6ff"},{token:"bracket",pattern:/\/?>/,light:"#24292e",dark:"#c9d1d9"}]}),i.register("js",{alias:"Javascript",rules:[{token:"comment",pattern:/\/\/[^\n]*|\/\*[\s\S]*?\*\//,light:"#6a737d",dark:"#8b949e"},{token:"string",pattern:/(?:'|"|`)(?:\\.|[^\\'"\b])*?(?:'|"|`)/,light:"#032f62",dark:"#98c379"},{token:"keyword",pattern:/\b(async|await|break|case|catch|class|const|continue|default|delete|do|else|export|extends|finally|for|function|if|import|in|instanceof|new|return|super|switch|this|throw|try|typeof|var|while|with|yield|let|static)\b/,light:"#d73a49",dark:"#ff7b72"},{token:"builtin",pattern:/\b(console|window|document|Math|JSON|true|false|null|undefined|Object|Array|Promise|Number|String|Boolean)\b/,light:"#e36209",dark:"#ffa657"},{token:"number",pattern:/\b(0x[\da-fA-F]+|0b[01]+|\d+(\.\d+)?)\b/,light:"#005cc5",dark:"#79c0ff"},{token:"func",pattern:/\b[a-zA-Z_]\w*(?=\s*\()/,light:"#6f42c1",dark:"#d2a8ff"},{token:"op",pattern:/[+\-*/%=<>!&|^~]+/,light:"#069598",dark:"#56b6c2"}]}),i.register("ts",{alias:"Typescript",rules:[{token:"comment",pattern:/\/\/[^\n]*|\/\*[\s\S]*?\*\//,light:"#6a737d",dark:"#8b949e"},{token:"string",pattern:/(?:'|"|`)(?:\\.|[^\\'"\b])*?(?:'|"|`)/,light:"#032f62",dark:"#98c379"},{token:"decorator",pattern:/@[a-zA-Z_]\w*/,light:"#953800",dark:"#ffa657"},{token:"keyword",pattern:/\b(abstract|as|async|await|break|case|catch|class|const|continue|debugger|declare|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|is|keyof|let|module|namespace|new|package|private|protected|public|readonly|return|set|static|super|switch|this|throw|try|type|typeof|var|while|with|yield)\b/,light:"#d73a49",dark:"#ff7b72"},{token:"builtin",pattern:/\b(any|boolean|never|number|string|symbol|unknown|void|undefined|null|true|false|console|window|document)\b/,light:"#e36209",dark:"#ffa657"},{token:"type",pattern:/\b[A-Z]\w*\b/,light:"#005cc5",dark:"#79c0ff"},{token:"number",pattern:/\b(0x[\da-fA-F]+|0b[01]+|\d+(\.\d+)?)\b/,light:"#005cc5",dark:"#79c0ff"},{token:"func",pattern:/\b[a-zA-Z_]\w*(?=\s*\()/,light:"#6f42c1",dark:"#d2a8ff"},{token:"op",pattern:/(\?\.|![:\.]|[+\-*/%=<>!&|^~]+)/,light:"#089ba6",dark:"#79c0ff"}]}),i.register("md",{alias:"Markdown",rules:[{token:"comment",pattern:/<!--[\s\S]*?-->/,light:"#6a737d",dark:"#8b949e"},{token:"heading",pattern:/(^|\n)(#{1,6})\s*(.+)/,light:"#e36209",dark:"#ffa657"},{token:"bold",pattern:/\*\*([^*]+)\*\*|__([^_]+)__/g,light:"#d73a49",dark:"#ff7b72"},{token:"italic",pattern:/\*([^*]+)\*|_([^_]+)_/g,light:"#032f62",dark:"#a5d6ff"},{token:"link",pattern:/\[([^\]]+)\]\(([^)]+)\)/g,light:"#0288d1",dark:"#80c0ff"},{token:"inline-code",pattern:/`([^`]+)`/g,light:"#032f62",dark:"#98c379"},{token:"code-block",pattern:/```([^\n]+)\n([\s\S]*?)```/g,light:"#24292e",dark:"#c9d1d9"},{token:"list-item",pattern:/(^|\n)([-*])\s+(.+)/g,light:"#5c6e7c",dark:"#8b949e"},{token:"quote",pattern:/(^|\n)>[ \t]*(.+)/g,light:"#6f42c1",dark:"#d2a8ff"},{token:"image",pattern:/!\[([^\]]+)\]\(([^)]+)\)/g,light:"#d73a49",dark:"#ff7b72"},{token:"hr",pattern:/^(---|___|\*\*\*)\s*$/gm,light:"#24292e",dark:"#c9d1d9"},{token:"strikethrough",pattern:/~~([^~]+)~~/g,light:"#e36209",dark:"#ffa657"},{token:"table",pattern:/\|([^\|]+)\|([^\|]+)\|/g,light:"#5c6e7c",dark:"#8b949e"}]}),i.addTools([n]),customElements.define(`${e}-code`,i),i});
|
|
File without changes
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
+
<title>Coax 代码高亮插件</title>
|
|
8
|
+
<style>
|
|
9
|
+
/* 白天模式变量 */
|
|
10
|
+
:root {}
|
|
11
|
+
</style>
|
|
12
|
+
|
|
13
|
+
</head>
|
|
14
|
+
|
|
15
|
+
<body>
|
|
16
|
+
<ax-code streaming tools="copy" indexed lang="js">
|
|
17
|
+
<code>
|
|
18
|
+
/**
|
|
19
|
+
* Simple animation function
|
|
20
|
+
*/
|
|
21
|
+
async function animate(element, duration) {
|
|
22
|
+
const start = Date.now();
|
|
23
|
+
|
|
24
|
+
if (!element) return false;
|
|
25
|
+
|
|
26
|
+
console.log("Animation started...");
|
|
27
|
+
|
|
28
|
+
while (Date.now() - start < duration) {
|
|
29
|
+
let progress = (Date.now() - start) / duration;
|
|
30
|
+
element.style.opacity = Math.min(progress, 1);
|
|
31
|
+
await Promise.resolve();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
</code>
|
|
37
|
+
</ax-code>
|
|
38
|
+
|
|
39
|
+
<button id="append01">尾部增加片段1</button>
|
|
40
|
+
<button id="append02">尾部增加片段2</button>
|
|
41
|
+
<button id="append03">尾部增加片段3</button>
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
<script src="../dist/coax.umd.js" type='text/javascript'></script>
|
|
46
|
+
<script type='text/javascript'>
|
|
47
|
+
|
|
48
|
+
let append01 = document.querySelector('#append01');
|
|
49
|
+
let append02 = document.querySelector('#append02');
|
|
50
|
+
let append03 = document.querySelector('#append03');
|
|
51
|
+
let code = document.querySelector('ax-code');
|
|
52
|
+
append01.onclick = () => {
|
|
53
|
+
code.append(`
|
|
54
|
+
function calculateCircleArea(radius) {
|
|
55
|
+
if (typeof radius !== 'number' || radius <= 0) {
|
|
56
|
+
throw new Error('Radius must be a positive number');
|
|
57
|
+
}
|
|
58
|
+
return Math.PI * radius * radius;
|
|
59
|
+
}`);
|
|
60
|
+
}
|
|
61
|
+
append02.onclick = () => {
|
|
62
|
+
code.append(`
|
|
63
|
+
function calculateCircleCircumference(radius) {
|
|
64
|
+
if (typeof radius !== 'number' || radius <= 0) {
|
|
65
|
+
throw new Error('Radius must be a positive number');
|
|
66
|
+
}
|
|
67
|
+
return 2 * Math.PI * radius;
|
|
68
|
+
}`);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
append03.onclick = () => {
|
|
72
|
+
code.append(`
|
|
73
|
+
while (Date.now() - start < duration) {
|
|
74
|
+
let progress = (Date.now() - start) / duration;
|
|
75
|
+
element.style.opacity = Math.min(progress, 1);
|
|
76
|
+
await Promise.resolve();
|
|
77
|
+
}`);
|
|
78
|
+
}
|
|
79
|
+
</script>
|
|
80
|
+
</body>
|
|
81
|
+
|
|
82
|
+
</html>
|
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8">
|
|
6
|
+
<title>Coax 语法高亮配色增强实验室</title>
|
|
7
|
+
<style>
|
|
8
|
+
:root {
|
|
9
|
+
--sidebar-width: 380px;
|
|
10
|
+
--primary-color: #007aff;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
body {
|
|
14
|
+
display: flex;
|
|
15
|
+
height: 100vh;
|
|
16
|
+
margin: 0;
|
|
17
|
+
background: #f5f5f7;
|
|
18
|
+
color: #1d1d1f;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/* 布局 */
|
|
22
|
+
#sidebar {
|
|
23
|
+
width: var(--sidebar-width);
|
|
24
|
+
background: white;
|
|
25
|
+
border-right: 1px solid #d2d2d7;
|
|
26
|
+
display: flex;
|
|
27
|
+
flex-direction: column;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
#preview-area {
|
|
31
|
+
flex: 1;
|
|
32
|
+
padding: 40px;
|
|
33
|
+
display: flex;
|
|
34
|
+
flex-direction: column;
|
|
35
|
+
gap: 20px;
|
|
36
|
+
overflow-y: auto;
|
|
37
|
+
transition: background 0.3s;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
#preview-area.dark {
|
|
41
|
+
background: #121212;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/* 侧边栏控件 */
|
|
45
|
+
.sidebar-header {
|
|
46
|
+
padding: 20px;
|
|
47
|
+
border-bottom: 1px solid #eee;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.lang-tabs {
|
|
51
|
+
display: flex;
|
|
52
|
+
background: #eee;
|
|
53
|
+
padding: 4px;
|
|
54
|
+
border-radius: 8px;
|
|
55
|
+
margin: 10px 20px;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.tab-btn {
|
|
59
|
+
flex: 1;
|
|
60
|
+
border: none;
|
|
61
|
+
padding: 8px;
|
|
62
|
+
border-radius: 6px;
|
|
63
|
+
cursor: pointer;
|
|
64
|
+
background: transparent;
|
|
65
|
+
font-size: 13px;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.tab-btn.active {
|
|
69
|
+
background: white;
|
|
70
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
71
|
+
font-weight: bold;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
#controls-list {
|
|
75
|
+
flex: 1;
|
|
76
|
+
overflow-y: auto;
|
|
77
|
+
padding: 0 20px 20px;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.control-item {
|
|
81
|
+
margin-top: 15px;
|
|
82
|
+
padding-bottom: 15px;
|
|
83
|
+
border-bottom: 1px solid #f5f5f5;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.control-item label {
|
|
87
|
+
display: block;
|
|
88
|
+
font-size: 12px;
|
|
89
|
+
font-weight: 600;
|
|
90
|
+
color: #86868b;
|
|
91
|
+
margin-bottom: 8px;
|
|
92
|
+
text-transform: uppercase;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.color-row {
|
|
96
|
+
display: flex;
|
|
97
|
+
align-items: center;
|
|
98
|
+
gap: 12px;
|
|
99
|
+
margin-bottom: 8px;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.color-row span {
|
|
103
|
+
font-size: 11px;
|
|
104
|
+
width: 40px;
|
|
105
|
+
color: #86868b;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.picker-wrapper {
|
|
109
|
+
display: flex;
|
|
110
|
+
align-items: center;
|
|
111
|
+
background: #f5f5f7;
|
|
112
|
+
padding: 4px 8px;
|
|
113
|
+
border-radius: 6px;
|
|
114
|
+
flex: 1;
|
|
115
|
+
cursor: pointer;
|
|
116
|
+
border: 1px solid transparent;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.picker-wrapper:hover {
|
|
120
|
+
border-color: #d2d2d7;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
input[type="color"] {
|
|
124
|
+
border: none;
|
|
125
|
+
width: 24px;
|
|
126
|
+
height: 24px;
|
|
127
|
+
background: none;
|
|
128
|
+
cursor: pointer;
|
|
129
|
+
padding: 0;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.hex-code {
|
|
133
|
+
font-family: monospace;
|
|
134
|
+
font-size: 13px;
|
|
135
|
+
margin-left: 8px;
|
|
136
|
+
flex: 1;
|
|
137
|
+
color: #1d1d1f;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.copy-btn {
|
|
141
|
+
border: none;
|
|
142
|
+
background: #eee;
|
|
143
|
+
font-size: 10px;
|
|
144
|
+
padding: 4px 8px;
|
|
145
|
+
border-radius: 4px;
|
|
146
|
+
cursor: pointer;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.copy-btn:hover {
|
|
150
|
+
background: #e2e2e7;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/* 预览代码盒 */
|
|
154
|
+
.code-container {
|
|
155
|
+
background: white;
|
|
156
|
+
border-radius: 12px;
|
|
157
|
+
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.08);
|
|
158
|
+
padding: 24px;
|
|
159
|
+
position: relative;
|
|
160
|
+
transition: 0.3s;
|
|
161
|
+
border: 1px solid #d2d2d7;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.dark .code-container {
|
|
165
|
+
background: #1e1e1e;
|
|
166
|
+
border-color: #333;
|
|
167
|
+
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.mode-toggle {
|
|
171
|
+
position: fixed;
|
|
172
|
+
bottom: 20px;
|
|
173
|
+
right: 20px;
|
|
174
|
+
padding: 12px 24px;
|
|
175
|
+
border-radius: 30px;
|
|
176
|
+
border: none;
|
|
177
|
+
background: var(--primary-color);
|
|
178
|
+
color: white;
|
|
179
|
+
cursor: pointer;
|
|
180
|
+
font-weight: 600;
|
|
181
|
+
box-shadow: 0 4px 12px rgba(0, 122, 255, 0.3);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/* 高亮 Token 占位符(通过动态 CSS 变量渲染) */
|
|
185
|
+
</style>
|
|
186
|
+
</head>
|
|
187
|
+
|
|
188
|
+
<body>
|
|
189
|
+
|
|
190
|
+
<div id="sidebar">
|
|
191
|
+
<div class="sidebar-header">
|
|
192
|
+
<h2 style="margin:0; font-size: 18px;">Coax 配色实验室</h2>
|
|
193
|
+
<p style="font-size: 12px; color: #86868b;">配置各语言 Token,点击 HEX 即可复制</p>
|
|
194
|
+
</div>
|
|
195
|
+
|
|
196
|
+
<div class="lang-tabs" id="lang-tabs">
|
|
197
|
+
<button class="tab-btn active" onclick="switchLang('html')">HTML</button>
|
|
198
|
+
<button class="tab-btn" onclick="switchLang('js')">JS</button>
|
|
199
|
+
<button class="tab-btn" onclick="switchLang('ts')">TS</button>
|
|
200
|
+
<button class="tab-btn" onclick="switchLang('css')">CSS</button>
|
|
201
|
+
</div>
|
|
202
|
+
|
|
203
|
+
<div id="controls-list"></div>
|
|
204
|
+
</div>
|
|
205
|
+
|
|
206
|
+
<div id="preview-area" id="preview-area">
|
|
207
|
+
<div class="code-container">
|
|
208
|
+
<ax-code></ax-code>
|
|
209
|
+
</div>
|
|
210
|
+
<button id="copy">复制主题样式</button>
|
|
211
|
+
<button id="reset">恢复原始样式</button>
|
|
212
|
+
</div>
|
|
213
|
+
|
|
214
|
+
<button class="mode-toggle" onclick="toggleDarkMode()">切换深色模式 (Current: Light)</button>
|
|
215
|
+
|
|
216
|
+
<script src="../dist/coax.umd.js" type='text/javascript'></script>
|
|
217
|
+
<script>
|
|
218
|
+
// 1. 核心数据结构:各语言的配置
|
|
219
|
+
const config = {
|
|
220
|
+
html: {
|
|
221
|
+
tokens: ['doctype', 'tag', 'attr', 'string', 'comment', 'bracket'],
|
|
222
|
+
// 包含 DOCTYPE, 注释, 标签, 属性, 字符串, 闭合括号
|
|
223
|
+
code: `<!--详情页面-->\n<!DOCTYPE html>\n<div class="main-wrapper" data-active="true">\n <h1 id="title">Coax Editor</h1>\n <img src="./assets/logo.svg" alt="Coax Logo" />\n <br />\n</div>`,
|
|
224
|
+
colors: {
|
|
225
|
+
doctype: { light: '#6a737d', dark: '#8b949e' }, // 灰度处理,弱化非结构信息
|
|
226
|
+
tag: { light: '#22863a', dark: '#7ee787' }, // 绿色(标签)
|
|
227
|
+
attr: { light: '#6f42c1', dark: '#d2a8ff' }, // 紫色(属性)
|
|
228
|
+
string: { light: '#032f62', dark: '#a5d6ff' }, // 蓝色(值)
|
|
229
|
+
comment: { light: '#999999', dark: '#6e7681' }, // 弱灰(注释)
|
|
230
|
+
bracket: { light: '#24292e', dark: '#c9d1d9' } // 默认色(括号)
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
js: {
|
|
234
|
+
tokens: ['keyword', 'func', 'string', 'builtin', 'number', 'comment', 'op'],
|
|
235
|
+
// 包含 关键字, 函数调用, 字符串, 内置对象, 数字, 注释, 运算符
|
|
236
|
+
code: `// 这是一个 JS 逻辑演示\nasync function fetchData(id) {\n const API = "https://api.coax.com/v1";\n let count = 2026 + id;\n if (count > 0) {\n console.log(\`Fetching \${id}...\`);\n return Math.random() * count;\n }\n return null;\n}`,
|
|
237
|
+
colors: {
|
|
238
|
+
keyword: { light: '#d73a49', dark: '#ff7b72' }, // 鲜红/浅粉(逻辑控制)
|
|
239
|
+
func: { light: '#6f42c1', dark: '#d2a8ff' }, // 紫色(定义与调用)
|
|
240
|
+
string: { light: '#032f62', dark: '#98c379' }, // 绿色(暗色下绿色字符串更护眼)
|
|
241
|
+
builtin: { light: '#e36209', dark: '#ffa657' }, // 橙色(内置变量)
|
|
242
|
+
number: { light: '#005cc5', dark: '#79c0ff' }, // 蓝色(数值)
|
|
243
|
+
comment: { light: '#6a737d', dark: '#8b949e' }, // 灰色(注释)
|
|
244
|
+
op: { light: '#069598', dark: '#56b6c2'} // 青色(将运算符与关键字区分开)
|
|
245
|
+
}
|
|
246
|
+
},
|
|
247
|
+
ts: {
|
|
248
|
+
tokens: ['type', 'decorator', 'keyword', 'func', 'string', 'builtin', 'number', 'comment', 'op'],
|
|
249
|
+
// 包含 类型声明, 装饰器, 关键字, 函数, 字符串, 内置, 数字, 注释, 运算符
|
|
250
|
+
code: `/** TypeScript 装饰器与类型演示 **/\n@Module({ providers: [] })\nexport class User<T> extends Base {\n readonly version: number = 1.0;\n private name: string = "Gemini";\n\n public async save(data: T): Promise<boolean> {\n const status = await this.exec();\n return !!status;\n }\n}`,
|
|
251
|
+
colors: {
|
|
252
|
+
keyword: { light: '#d73a49', dark: '#ff7b72' },
|
|
253
|
+
func: { light: '#6f42c1', dark: '#d2a8ff' },
|
|
254
|
+
type: { light: '#005cc5', dark: '#79c0ff' }, // 蓝色(TS 核心:类型)
|
|
255
|
+
builtin: { light: '#e36209', dark: '#ffa657' },
|
|
256
|
+
decorator: { light: '#953800', dark: '#ffa657' },// 棕/橙(装饰器)
|
|
257
|
+
number: { light: '#005cc5', dark: '#79c0ff' },
|
|
258
|
+
string: { light: '#032f62', dark: '#98c379' },
|
|
259
|
+
comment: { light: '#6a737d', dark: '#8b949e' },
|
|
260
|
+
op: { light: '#089ba6', dark: '#79c0ff'}
|
|
261
|
+
}
|
|
262
|
+
},
|
|
263
|
+
css: {
|
|
264
|
+
tokens: ['selector', 'property', 'value', 'unit', 'comment', 'number', 'func', 'punct'],
|
|
265
|
+
// 包含 选择器, 属性, 值, 单位, 注释, 数字, 函数, 标点
|
|
266
|
+
code: `/* 响应式样式 */\n@media (max-width: 768px) {\n .container > #main:hover {\n background: rgba(0, 0, 0, 0.05);\n margin: 10px 2rem;\n width: calc(100% - 20px);\n font-family: "Consolas", sans-serif;\n }\n}`,
|
|
267
|
+
colors: {
|
|
268
|
+
selector: { light: '#22863a', dark: '#7ee787' }, // 绿色(CSS 选择器)
|
|
269
|
+
property: { light: '#005cc5', dark: '#79c0ff' }, // 蓝色(属性名)
|
|
270
|
+
value: { light: '#032f62', dark: '#a5d6ff' }, // 浅蓝/深蓝(属性值)
|
|
271
|
+
unit: { light: '#d73a49', dark: '#ff7b72' }, // 红色(单位 px, rem)
|
|
272
|
+
number: { light: '#d73a49', dark: '#ff7b72' }, // 红色(纯数字)
|
|
273
|
+
func: { light: '#6f42c1', dark: '#d2a8ff' }, // 紫色(calc, rgba)
|
|
274
|
+
comment: { light: '#6a737d', dark: '#8b949e' },
|
|
275
|
+
punct: { light: '#24292e', dark: '#c9d1d9' } // 默认/白(分号、括号)
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
let currentLang = 'html';
|
|
281
|
+
let isDark = false;
|
|
282
|
+
let codeEl = document.querySelector('ax-code');
|
|
283
|
+
let copyEl = document.querySelector('#copy');
|
|
284
|
+
let resetEl = document.querySelector('#reset');
|
|
285
|
+
let currentStyle = '';
|
|
286
|
+
|
|
287
|
+
// 2. 初始化渲染
|
|
288
|
+
function init() {
|
|
289
|
+
renderControls();
|
|
290
|
+
renderCode();
|
|
291
|
+
updateDynamicStyles();
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// 切换语言标签
|
|
295
|
+
function switchLang(lang) {
|
|
296
|
+
currentLang = lang;
|
|
297
|
+
document.querySelectorAll('.tab-btn').forEach(btn => {
|
|
298
|
+
btn.classList.toggle('active', btn.innerText.toLowerCase() === lang);
|
|
299
|
+
});
|
|
300
|
+
renderControls();
|
|
301
|
+
renderCode();
|
|
302
|
+
updateDynamicStyles();
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// 渲染左侧色值控件
|
|
306
|
+
function renderControls() {
|
|
307
|
+
const list = document.getElementById('controls-list');
|
|
308
|
+
list.innerHTML = '';
|
|
309
|
+
const langConfig = config[currentLang];
|
|
310
|
+
|
|
311
|
+
langConfig.tokens.forEach(token => {
|
|
312
|
+
const item = document.createElement('div');
|
|
313
|
+
item.className = 'control-item';
|
|
314
|
+
const colors = langConfig.colors[token];
|
|
315
|
+
|
|
316
|
+
item.innerHTML = `
|
|
317
|
+
<label>${token}</label>
|
|
318
|
+
${renderColorRow(token, 'light', colors.light)}
|
|
319
|
+
${renderColorRow(token, 'dark', colors.dark)}
|
|
320
|
+
`;
|
|
321
|
+
list.appendChild(item);
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
function renderColorRow(token, mode, value) {
|
|
326
|
+
return `
|
|
327
|
+
<div class="color-row">
|
|
328
|
+
<span>${mode.toLowerCase()}</span>
|
|
329
|
+
<div class="picker-wrapper">
|
|
330
|
+
<input type="color" value="${value}" oninput="updateTokenColor('${token}', '${mode}', this.value)">
|
|
331
|
+
<div class="hex-code" onclick="copyHex(this.previousElementSibling.value)">${value.toLowerCase()}</div>
|
|
332
|
+
<button class="copy-btn" onclick="copyHex(this.previousElementSibling.previousElementSibling.value)">COPY</button>
|
|
333
|
+
</div>
|
|
334
|
+
</div>
|
|
335
|
+
`;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// 3. 颜色更新逻辑
|
|
339
|
+
function updateTokenColor(token, mode, value) {
|
|
340
|
+
config[currentLang].colors[token][mode] = value;
|
|
341
|
+
// 实时更新文字显示,不重新渲染整个列表以免失去焦点
|
|
342
|
+
event.target.nextElementSibling.innerText = value.toLowerCase();
|
|
343
|
+
updateDynamicStyles();
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// 4. 复制功能
|
|
347
|
+
async function copyHex(hex) {
|
|
348
|
+
try {
|
|
349
|
+
await navigator.clipboard.writeText(hex.toLowerCase());
|
|
350
|
+
alert('色值已复制: ' + hex.toLowerCase());
|
|
351
|
+
} catch (err) {
|
|
352
|
+
console.error('无法复制', err);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// 5. 动态生成 CSS 变量
|
|
357
|
+
function updateDynamicStyles() {
|
|
358
|
+
currentStyle = ':root{\n';
|
|
359
|
+
const langConfig = config[currentLang];
|
|
360
|
+
|
|
361
|
+
langConfig.tokens.forEach(token => {
|
|
362
|
+
const color = isDark ? langConfig.colors[token].dark : langConfig.colors[token].light;
|
|
363
|
+
|
|
364
|
+
currentStyle += `--ax-${currentLang}-${token}: ${color};\n`;
|
|
365
|
+
|
|
366
|
+
});
|
|
367
|
+
currentStyle += '}';
|
|
368
|
+
|
|
369
|
+
let styleTag = document.getElementById('dynamic-colors');
|
|
370
|
+
if (!styleTag) {
|
|
371
|
+
styleTag = document.createElement('style');
|
|
372
|
+
styleTag.id = 'dynamic-colors';
|
|
373
|
+
document.head.appendChild(styleTag);
|
|
374
|
+
}
|
|
375
|
+
styleTag.textContent = currentStyle;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// 6. 简单的代码预览生成(模拟高亮逻辑)
|
|
379
|
+
function renderCode() {
|
|
380
|
+
const langConfig = config[currentLang];
|
|
381
|
+
let html = langConfig.code
|
|
382
|
+
.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
383
|
+
|
|
384
|
+
codeEl.replaceCode(html);
|
|
385
|
+
codeEl.setAttribute('lang', currentLang);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
function toggleDarkMode() {
|
|
389
|
+
isDark = !isDark;
|
|
390
|
+
document.getElementById('preview-area').classList.toggle('dark', isDark);
|
|
391
|
+
document.querySelector('.mode-toggle').innerText = `切换深色模式 (Current: ${isDark ? 'Dark' : 'Light'})`;
|
|
392
|
+
updateDynamicStyles();
|
|
393
|
+
renderControls(); // 重新渲染列表以更新文字状态(可选)
|
|
394
|
+
isDark ? codeEl.setAttribute('scheme', 'dark') : codeEl.removeAttribute('scheme');
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
copyEl.onclick = () => {
|
|
398
|
+
navigator.clipboard.writeText(currentStyle)
|
|
399
|
+
.then(() => {
|
|
400
|
+
alert('已经复制到剪切板,可粘贴到文本文件当中');
|
|
401
|
+
})
|
|
402
|
+
}
|
|
403
|
+
resetEl.onclick = () => {
|
|
404
|
+
document.querySelector('#dynamic-colors')?.remove();
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
init();
|
|
408
|
+
</script>
|
|
409
|
+
|
|
410
|
+
</body>
|
|
411
|
+
|
|
412
|
+
</html>
|
|
@@ -7,24 +7,7 @@
|
|
|
7
7
|
<title>Coax 代码高亮插件</title>
|
|
8
8
|
<style>
|
|
9
9
|
/* 白天模式变量 */
|
|
10
|
-
:root {
|
|
11
|
-
--ax-css-selector: #6f42c1;
|
|
12
|
-
/* 紫色:选择器最显眼 */
|
|
13
|
-
--ax-css-property: #005cc5;
|
|
14
|
-
/* 蓝色:属性名 */
|
|
15
|
-
--ax-css-string: #22863a;
|
|
16
|
-
/* 绿色:内容字符串 */
|
|
17
|
-
--ax-css-unit: #d73a49;
|
|
18
|
-
/* 红色:单位(如 px, rem) */
|
|
19
|
-
--ax-css-number: #005cc5;
|
|
20
|
-
/* 蓝色:数值 */
|
|
21
|
-
--ax-css-func: #e36209;
|
|
22
|
-
/* 橙色:函数如 var(), rgba() */
|
|
23
|
-
--ax-css-comment: #6a737d;
|
|
24
|
-
/* 灰色:注释 */
|
|
25
|
-
--ax-css-punct: #24292e;
|
|
26
|
-
/* 深灰:符号 */
|
|
27
|
-
}
|
|
10
|
+
:root {}
|
|
28
11
|
</style>
|
|
29
12
|
|
|
30
13
|
</head>
|
|
@@ -56,6 +39,7 @@
|
|
|
56
39
|
<script src="../dist/coax.umd.js" type='text/javascript'></script>
|
|
57
40
|
<script type='text/javascript'>
|
|
58
41
|
|
|
42
|
+
|
|
59
43
|
</script>
|
|
60
44
|
</body>
|
|
61
45
|
|