拼ui 一些业务逻辑x实现
This commit is contained in:
@@ -0,0 +1,602 @@
|
||||
(function(){
|
||||
const state = {
|
||||
chapters: [],
|
||||
activeId: null,
|
||||
search: '',
|
||||
expandedGroups: new Set(),
|
||||
lang: 'zh'
|
||||
};
|
||||
|
||||
const GROUP_STORAGE_KEY = 'easychart_manual_nav_groups_v2';
|
||||
const LANG_STORAGE_KEY = 'easychart_manual_lang_v1';
|
||||
|
||||
const GROUPS = [
|
||||
{ key: 'workflow', title: '概览' },
|
||||
{ key: 'editor_ui', title: '编辑界面说明' },
|
||||
{ key: 'charts', title: 'Series详细配置' },
|
||||
{ key: 'reference', title: '配置项参考' },
|
||||
{ key: 'other', title: '其他' }
|
||||
];
|
||||
|
||||
const I18N = {
|
||||
zh: {
|
||||
searchPlaceholder: '搜索章节...',
|
||||
onThisPage: '本页目录',
|
||||
noHeadings: '没有标题',
|
||||
noChapters: '未找到任何手册章节。请将 Markdown 放到 Assets/EasyChart/Docs/Manual',
|
||||
groups: {
|
||||
workflow: '概览',
|
||||
editor_ui: '编辑界面说明',
|
||||
charts: 'Series详细配置',
|
||||
reference: '配置项参考',
|
||||
other: '其他'
|
||||
}
|
||||
},
|
||||
en: {
|
||||
searchPlaceholder: 'Search chapters...',
|
||||
onThisPage: 'On this page',
|
||||
noHeadings: 'No headings',
|
||||
noChapters: 'No manual chapters found. Put Markdown under Assets/EasyChart/Docs/Manual',
|
||||
groups: {
|
||||
workflow: 'Overview',
|
||||
editor_ui: 'Editor UI',
|
||||
charts: 'Series',
|
||||
reference: 'Reference',
|
||||
other: 'Other'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function t(){
|
||||
const lang = state.lang || 'zh';
|
||||
return I18N[lang] || I18N.zh;
|
||||
}
|
||||
|
||||
function loadLang(){
|
||||
try{
|
||||
const raw = localStorage.getItem(LANG_STORAGE_KEY);
|
||||
if(raw === 'en' || raw === 'zh') state.lang = raw;
|
||||
}catch(_){
|
||||
}
|
||||
}
|
||||
|
||||
function saveLang(lang){
|
||||
try{
|
||||
localStorage.setItem(LANG_STORAGE_KEY, lang);
|
||||
}catch(_){
|
||||
}
|
||||
}
|
||||
|
||||
function getManualDataForLang(lang){
|
||||
if(lang === 'en' && window.EASYCHART_MANUAL_EN) return window.EASYCHART_MANUAL_EN;
|
||||
if(lang === 'zh' && window.EASYCHART_MANUAL_ZH) return window.EASYCHART_MANUAL_ZH;
|
||||
return window.EASYCHART_MANUAL || {};
|
||||
}
|
||||
|
||||
function ensureManualDataForLang(lang, done){
|
||||
try{
|
||||
const has = (lang === 'en') ? !!window.EASYCHART_MANUAL_EN : !!window.EASYCHART_MANUAL_ZH;
|
||||
if(has){ done(); return; }
|
||||
const s = document.createElement('script');
|
||||
s.src = `./manual-data.${lang}.js?t=${Date.now()}`;
|
||||
s.onload = done;
|
||||
s.onerror = done;
|
||||
document.body.appendChild(s);
|
||||
}catch(_){
|
||||
done();
|
||||
}
|
||||
}
|
||||
|
||||
function setChaptersFromManualData(manual){
|
||||
const data = (manual && manual.chapters) ? manual.chapters : [];
|
||||
state.chapters = data.map(ch => {
|
||||
const id = ch.id || '';
|
||||
return {
|
||||
id: id,
|
||||
relPath: ch.relPath || '',
|
||||
title: ch.title || id,
|
||||
content: ch.content || ''
|
||||
};
|
||||
});
|
||||
state.chapters.sort(compareChapters);
|
||||
|
||||
if(state.activeId){
|
||||
const exists = state.chapters.some(c => c.id === state.activeId);
|
||||
if(!exists && state.chapters.length > 0) state.activeId = state.chapters[0].id;
|
||||
}
|
||||
}
|
||||
|
||||
function getNavConfig(){
|
||||
try{
|
||||
const nav = window.EASYCHART_MANUAL_NAV;
|
||||
if(!nav || !Array.isArray(nav.groups)) return null;
|
||||
const groups = nav.groups
|
||||
.filter(g => g && typeof g.key === 'string' && typeof g.title === 'string' && Array.isArray(g.items))
|
||||
.map(g => ({ key: g.key, title: g.title, items: g.items.filter(x => typeof x === 'string') }));
|
||||
if(groups.length <= 0) return null;
|
||||
return { groups };
|
||||
}catch(_){
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function normalizeNavGroups(groups){
|
||||
const dict = t();
|
||||
return (groups || []).map(g => {
|
||||
const title = (dict.groups && dict.groups[g.key]) ? dict.groups[g.key] : (g.title || g.key);
|
||||
return { key: g.key, title, items: g.items };
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function loadExpandedGroups(){
|
||||
try{
|
||||
const raw = localStorage.getItem(GROUP_STORAGE_KEY);
|
||||
if(!raw) return;
|
||||
const arr = JSON.parse(raw);
|
||||
if(Array.isArray(arr)){
|
||||
state.expandedGroups = new Set(arr.filter(x => typeof x === 'string'));
|
||||
}
|
||||
}catch(_){
|
||||
}
|
||||
}
|
||||
|
||||
function saveExpandedGroups(){
|
||||
try{
|
||||
localStorage.setItem(GROUP_STORAGE_KEY, JSON.stringify(Array.from(state.expandedGroups)));
|
||||
}catch(_){
|
||||
}
|
||||
}
|
||||
|
||||
function ensureDefaultExpanded(){
|
||||
if(state.expandedGroups.size > 0) return;
|
||||
const nav = getNavConfig();
|
||||
const groups = (nav && nav.groups) ? nav.groups : GROUPS;
|
||||
for(let i=0;i<groups.length;i++){
|
||||
const g = groups[i];
|
||||
if(!g || !g.key) continue;
|
||||
if(g.key === 'other') continue;
|
||||
state.expandedGroups.add(g.key);
|
||||
}
|
||||
}
|
||||
|
||||
function escapeHtml(s){
|
||||
return (s||'').replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
|
||||
}
|
||||
|
||||
function escapeAttr(s){
|
||||
return escapeHtml(s).replace(/"/g,'"');
|
||||
}
|
||||
|
||||
function slugify(text){
|
||||
const s = (text||'').toLowerCase().trim();
|
||||
return s
|
||||
.replace(/[^a-z0-9\s-_]/g,'')
|
||||
.replace(/[\s_]+/g,'-')
|
||||
.replace(/-+/g,'-') || 'h';
|
||||
}
|
||||
|
||||
function getFileName(relPath){
|
||||
return (relPath || '').replace(/\\/g,'/').replace(/.*\//,'');
|
||||
}
|
||||
|
||||
function getNavTitle(ch){
|
||||
const t = (ch && ch.title) ? String(ch.title) : '';
|
||||
return t.replace(/^\s*\d+\s*-\s*/,'').trim() || t;
|
||||
}
|
||||
|
||||
function getChapterNumber(relPath){
|
||||
const name = getFileName(relPath);
|
||||
const m = name.match(/^(\d+)[-_]/);
|
||||
if(!m) return Number.POSITIVE_INFINITY;
|
||||
const n = parseInt(m[1], 10);
|
||||
return Number.isFinite(n) ? n : Number.POSITIVE_INFINITY;
|
||||
}
|
||||
|
||||
function compareChapters(a, b){
|
||||
const an = getChapterNumber(a.relPath);
|
||||
const bn = getChapterNumber(b.relPath);
|
||||
if(an !== bn) return an - bn;
|
||||
const at = getNavTitle(a).toLowerCase();
|
||||
const bt = getNavTitle(b).toLowerCase();
|
||||
if(at < bt) return -1;
|
||||
if(at > bt) return 1;
|
||||
return (a.id || '').localeCompare((b.id || ''), undefined, { sensitivity: 'base' });
|
||||
}
|
||||
|
||||
function compareChaptersInGroup(groupKey, a, b){
|
||||
return compareChapters(a, b);
|
||||
}
|
||||
|
||||
function getGroupKey(ch){
|
||||
const n = getChapterNumber(ch.relPath);
|
||||
if(n >= 0 && n <= 1) return 'workflow';
|
||||
if(n === 2 || (n >= 20 && n <= 29)) return 'editor_ui';
|
||||
if(n >= 10 && n <= 19) return 'charts';
|
||||
if(n >= 3 && n <= 9) return 'reference';
|
||||
return 'other';
|
||||
}
|
||||
|
||||
function buildGroups(chapters){
|
||||
const nav = getNavConfig();
|
||||
if(nav && nav.groups){
|
||||
const groupDefs = normalizeNavGroups(nav.groups);
|
||||
const map = new Map();
|
||||
const idToGroup = new Map();
|
||||
const groupOrder = [];
|
||||
|
||||
groupDefs.forEach(g => {
|
||||
map.set(g.key, { key: g.key, title: g.title, children: [] });
|
||||
groupOrder.push(g.key);
|
||||
for(let i=0;i<g.items.length;i++){
|
||||
const id = g.items[i];
|
||||
if(!idToGroup.has(id)) idToGroup.set(id, { key: g.key, index: i });
|
||||
}
|
||||
});
|
||||
|
||||
const otherKey = map.has('other') ? 'other' : null;
|
||||
if(!otherKey){
|
||||
map.set('other', { key: 'other', title: '其他', children: [] });
|
||||
groupOrder.push('other');
|
||||
}
|
||||
|
||||
chapters.forEach(ch => {
|
||||
const hit = idToGroup.get(ch.id);
|
||||
const key = hit ? hit.key : 'other';
|
||||
if(!map.has(key)) map.set(key, { key, title: key, children: [] });
|
||||
map.get(key).children.push(ch);
|
||||
});
|
||||
|
||||
groupDefs.forEach(g => {
|
||||
const orderMap = new Map();
|
||||
for(let i=0;i<g.items.length;i++) orderMap.set(g.items[i], i);
|
||||
const grp = map.get(g.key);
|
||||
if(!grp) return;
|
||||
grp.children.sort((a, b) => {
|
||||
const ai = orderMap.has(a.id) ? orderMap.get(a.id) : Number.POSITIVE_INFINITY;
|
||||
const bi = orderMap.has(b.id) ? orderMap.get(b.id) : Number.POSITIVE_INFINITY;
|
||||
if(ai !== bi) return ai - bi;
|
||||
return compareChapters(a, b);
|
||||
});
|
||||
});
|
||||
|
||||
const otherGrp = map.get('other');
|
||||
if(otherGrp) otherGrp.children.sort((a, b) => compareChaptersInGroup('other', a, b));
|
||||
return groupOrder.map(k => map.get(k)).filter(g => g && g.children.length > 0);
|
||||
}
|
||||
|
||||
const map = new Map();
|
||||
const fallbackGroups = normalizeNavGroups(GROUPS);
|
||||
fallbackGroups.forEach(g => map.set(g.key, { key: g.key, title: g.title, children: [] }));
|
||||
chapters.forEach(ch => {
|
||||
const key = getGroupKey(ch);
|
||||
if(!map.has(key)) map.set(key, { key, title: key, children: [] });
|
||||
map.get(key).children.push(ch);
|
||||
});
|
||||
map.forEach(g => g.children.sort((a, b) => compareChaptersInGroup(g.key, a, b)));
|
||||
return fallbackGroups.map(g => map.get(g.key)).filter(g => g && g.children.length > 0);
|
||||
}
|
||||
|
||||
function inlineToHtml(text){
|
||||
if(!text) return '';
|
||||
let out = escapeHtml(text);
|
||||
|
||||
out = out.replace(/`([^`]+)`/g, (m, g1) => `<code class="inline">${g1}</code>`);
|
||||
out = out.replace(/\*\*([^*]+)\*\*/g, (m, g1) => `<strong>${g1}</strong>`);
|
||||
out = out.replace(/(^|[^*])\*([^*]+)\*([^*]|$)/g, (m, p1, g1, p2) => `${p1}<em>${g1}</em>${p2}`);
|
||||
|
||||
out = out.replace(/\[(?<t>[^\]]+)\]\((?<u>[^\)]+)\)/g, (m, _1, _2, _3, _4, groups) => {
|
||||
const t = groups.t;
|
||||
let u = groups.u;
|
||||
u = u.replace(/\\/g,'/');
|
||||
|
||||
if(u.endsWith('.md')){
|
||||
const id = u.replace(/.*\//,'').replace(/\.md$/,'');
|
||||
return `<a href="#/${encodeURIComponent(id)}">${t}</a>`;
|
||||
}
|
||||
|
||||
const mdAnchor = u.match(/([^#]+)\.md#(.+)$/);
|
||||
if(mdAnchor){
|
||||
const id = mdAnchor[1].replace(/.*\//,'');
|
||||
const anchor = mdAnchor[2];
|
||||
return `<a href="#/${encodeURIComponent(id)}#${encodeURIComponent(anchor)}">${t}</a>`;
|
||||
}
|
||||
|
||||
if(u.startsWith('#')){
|
||||
return `<a href="${escapeAttr(u)}">${t}</a>`;
|
||||
}
|
||||
|
||||
return `<a href="${escapeAttr(u)}" target="_blank" rel="noreferrer">${t}</a>`;
|
||||
});
|
||||
return out;
|
||||
}
|
||||
|
||||
function markdownToHtml(md){
|
||||
if(!md) return '';
|
||||
const lines = md.replace(/\r\n/g,'\n').replace(/\r/g,'\n').split('\n');
|
||||
|
||||
let inCode = false;
|
||||
let inUl = false;
|
||||
let inOl = false;
|
||||
let para = '';
|
||||
|
||||
const parts = [];
|
||||
|
||||
function flushPara(){
|
||||
if(!para.trim()) return;
|
||||
parts.push(`<p>${inlineToHtml(para.trim())}</p>`);
|
||||
para = '';
|
||||
}
|
||||
|
||||
function closeLists(){
|
||||
if(inUl){ parts.push('</ul>'); inUl = false; }
|
||||
if(inOl){ parts.push('</ol>'); inOl = false; }
|
||||
}
|
||||
|
||||
for(let i=0;i<lines.length;i++){
|
||||
const raw = lines[i] || '';
|
||||
const t = raw.replace(/\s+$/,'');
|
||||
|
||||
if(t.trimStart().startsWith('```')){
|
||||
if(!inCode){
|
||||
flushPara();
|
||||
closeLists();
|
||||
inCode = true;
|
||||
parts.push('<pre><code>');
|
||||
}else{
|
||||
inCode = false;
|
||||
parts.push('</code></pre>');
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if(inCode){
|
||||
parts.push(escapeHtml(t) + '\n');
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!t.trim()){
|
||||
flushPara();
|
||||
closeLists();
|
||||
continue;
|
||||
}
|
||||
|
||||
if(t.startsWith('>')){
|
||||
flushPara();
|
||||
closeLists();
|
||||
const qt = t.replace(/^>\s?/, '').trim();
|
||||
parts.push(`<blockquote>${inlineToHtml(qt)}</blockquote>`);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(t.startsWith('---')){
|
||||
flushPara();
|
||||
closeLists();
|
||||
parts.push('<hr/>');
|
||||
continue;
|
||||
}
|
||||
|
||||
if(t.startsWith('#')){
|
||||
flushPara();
|
||||
closeLists();
|
||||
let level = 0;
|
||||
while(level < t.length && t[level] === '#') level++;
|
||||
level = Math.max(1, Math.min(3, level));
|
||||
const text = t.slice(level).trim();
|
||||
const id = slugify(text);
|
||||
parts.push(`<h${level} id="${id}">${inlineToHtml(text)}</h${level}>`);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(t.startsWith('- ') || t.startsWith('* ')){
|
||||
flushPara();
|
||||
if(inOl){ parts.push('</ol>'); inOl = false; }
|
||||
if(!inUl){ parts.push('<ul>'); inUl = true; }
|
||||
parts.push(`<li>${inlineToHtml(t.slice(2).trim())}</li>`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const m = t.match(/^(\d+)\.\s+(.+)$/);
|
||||
if(m){
|
||||
flushPara();
|
||||
if(inUl){ parts.push('</ul>'); inUl = false; }
|
||||
if(!inOl){ parts.push('<ol>'); inOl = true; }
|
||||
parts.push(`<li>${inlineToHtml(m[2].trim())}</li>`);
|
||||
continue;
|
||||
}
|
||||
|
||||
para += (para ? ' ' : '') + t.trim();
|
||||
}
|
||||
|
||||
flushPara();
|
||||
closeLists();
|
||||
if(inCode) parts.push('</code></pre>');
|
||||
|
||||
return parts.join('');
|
||||
}
|
||||
|
||||
function buildTocFromContent(root){
|
||||
const toc = [];
|
||||
const hs = root.querySelectorAll('h1, h2, h3');
|
||||
hs.forEach(h => {
|
||||
const level = Number(h.tagName.slice(1));
|
||||
const title = h.textContent || '';
|
||||
const id = h.getAttribute('id') || '';
|
||||
if(!id) return;
|
||||
toc.push({level, title, id});
|
||||
});
|
||||
return toc;
|
||||
}
|
||||
|
||||
function render(){
|
||||
const nav = document.getElementById('nav');
|
||||
const content = document.getElementById('content');
|
||||
const tocEl = document.getElementById('toc');
|
||||
const dict = t();
|
||||
const search = (state.search || '').toLowerCase().trim();
|
||||
|
||||
const searchInput = document.getElementById('search');
|
||||
if(searchInput) searchInput.placeholder = dict.searchPlaceholder;
|
||||
|
||||
nav.innerHTML = '';
|
||||
const visible = state.chapters.filter(ch => {
|
||||
if(!search) return true;
|
||||
return (ch.title||'').toLowerCase().includes(search) || getNavTitle(ch).toLowerCase().includes(search) || (ch.relPath||'').toLowerCase().includes(search);
|
||||
});
|
||||
|
||||
const groups = buildGroups(visible);
|
||||
const forceExpand = !!search;
|
||||
|
||||
groups.forEach(g => {
|
||||
const header = document.createElement('button');
|
||||
header.type = 'button';
|
||||
header.className = 'nav-group-header';
|
||||
|
||||
const toggle = document.createElement('span');
|
||||
toggle.className = 'nav-group-toggle';
|
||||
header.appendChild(toggle);
|
||||
|
||||
const title = document.createElement('span');
|
||||
title.className = 'nav-group-title';
|
||||
title.textContent = g.title;
|
||||
header.appendChild(title);
|
||||
|
||||
const expanded = forceExpand || state.expandedGroups.has(g.key);
|
||||
header.setAttribute('data-expanded', expanded ? 'true' : 'false');
|
||||
|
||||
header.addEventListener('click', () => {
|
||||
const nowExpanded = !(header.getAttribute('data-expanded') === 'true');
|
||||
header.setAttribute('data-expanded', nowExpanded ? 'true' : 'false');
|
||||
if(nowExpanded) state.expandedGroups.add(g.key);
|
||||
else state.expandedGroups.delete(g.key);
|
||||
saveExpandedGroups();
|
||||
render();
|
||||
});
|
||||
|
||||
const groupWrap = document.createElement('div');
|
||||
groupWrap.className = 'nav-group';
|
||||
groupWrap.appendChild(header);
|
||||
|
||||
const children = document.createElement('div');
|
||||
children.className = 'nav-children';
|
||||
children.style.display = expanded ? 'block' : 'none';
|
||||
|
||||
g.children.forEach(ch => {
|
||||
const a = document.createElement('a');
|
||||
a.className = 'nav-item' + (ch.id === state.activeId ? ' active' : '');
|
||||
a.href = `#/${encodeURIComponent(ch.id)}`;
|
||||
a.textContent = getNavTitle(ch);
|
||||
children.appendChild(a);
|
||||
});
|
||||
|
||||
groupWrap.appendChild(children);
|
||||
nav.appendChild(groupWrap);
|
||||
});
|
||||
|
||||
const active = state.chapters.find(c => c.id === state.activeId) || visible[0] || state.chapters[0];
|
||||
if(!active){
|
||||
content.innerHTML = '<div class="notice">' + escapeHtml(dict.noChapters) + '</div>';
|
||||
tocEl.innerHTML = '';
|
||||
return;
|
||||
}
|
||||
|
||||
if(active.id !== state.activeId){
|
||||
state.activeId = active.id;
|
||||
location.hash = `#/${encodeURIComponent(active.id)}`;
|
||||
return;
|
||||
}
|
||||
|
||||
const html = markdownToHtml(active.content);
|
||||
content.innerHTML = html;
|
||||
|
||||
const toc = buildTocFromContent(content);
|
||||
tocEl.innerHTML = '';
|
||||
if(toc.length > 0){
|
||||
const title = document.createElement('div');
|
||||
title.className = 'toc-title';
|
||||
title.textContent = dict.onThisPage;
|
||||
tocEl.appendChild(title);
|
||||
|
||||
toc.forEach(it => {
|
||||
const a = document.createElement('a');
|
||||
a.href = `#/${encodeURIComponent(active.id)}#${encodeURIComponent(it.id)}`;
|
||||
a.textContent = it.title;
|
||||
a.style.paddingLeft = (it.level - 1) * 10 + 'px';
|
||||
tocEl.appendChild(a);
|
||||
});
|
||||
}else{
|
||||
tocEl.innerHTML = '<div class="toc-title">' + escapeHtml(dict.onThisPage) + '</div><div class="notice">' + escapeHtml(dict.noHeadings) + '</div>';
|
||||
}
|
||||
|
||||
const anchor = decodeURIComponent((location.hash.split('#')[2] || '').trim());
|
||||
if(anchor){
|
||||
const el = document.getElementById(anchor);
|
||||
if(el) el.scrollIntoView({block:'start'});
|
||||
}else{
|
||||
window.scrollTo(0,0);
|
||||
}
|
||||
}
|
||||
|
||||
function syncFromHash(){
|
||||
const h = location.hash || '';
|
||||
const m = h.match(/^#\/([^#]+)/);
|
||||
if(m && m[1]){
|
||||
state.activeId = decodeURIComponent(m[1]);
|
||||
}
|
||||
}
|
||||
|
||||
function init(){
|
||||
loadLang();
|
||||
|
||||
try{
|
||||
const req = window.EASYCHART_MANUAL_OPEN || {};
|
||||
const hasHash = !!(location.hash && location.hash.length > 1);
|
||||
if(!hasHash && req && req.chapterId){
|
||||
location.hash = `#/${encodeURIComponent(req.chapterId)}` + (req.anchor ? `#${encodeURIComponent(req.anchor)}` : '');
|
||||
}
|
||||
}catch(_){
|
||||
}
|
||||
|
||||
setChaptersFromManualData(getManualDataForLang(state.lang));
|
||||
loadExpandedGroups();
|
||||
ensureDefaultExpanded();
|
||||
|
||||
const langSelect = document.getElementById('lang');
|
||||
if(langSelect){
|
||||
langSelect.value = (state.lang === 'en') ? 'en' : 'zh';
|
||||
langSelect.addEventListener('change', () => {
|
||||
state.lang = (langSelect.value === 'en') ? 'en' : 'zh';
|
||||
saveLang(state.lang);
|
||||
ensureManualDataForLang(state.lang, () => {
|
||||
setChaptersFromManualData(getManualDataForLang(state.lang));
|
||||
syncFromHash();
|
||||
render();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const searchInput = document.getElementById('search');
|
||||
if(searchInput){
|
||||
searchInput.addEventListener('input', () => {
|
||||
state.search = searchInput.value || '';
|
||||
render();
|
||||
});
|
||||
}
|
||||
|
||||
window.addEventListener('hashchange', () => {
|
||||
syncFromHash();
|
||||
render();
|
||||
});
|
||||
|
||||
syncFromHash();
|
||||
if(!state.activeId && state.chapters.length > 0) state.activeId = state.chapters[0].id;
|
||||
render();
|
||||
}
|
||||
|
||||
if(document.readyState === 'loading'){
|
||||
document.addEventListener('DOMContentLoaded', init);
|
||||
}else{
|
||||
init();
|
||||
}
|
||||
})();
|
||||
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 94f73e6708080a74f9932b5538a77359
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 359794
|
||||
packageName: Easy Chart Lite
|
||||
packageVersion: 1.0
|
||||
assetPath: Assets/EasyChart/Docs/ManualWeb/app.js
|
||||
uploadId: 857482
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b29bc9a50db798141a2e1ebdb79d812d
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 359794
|
||||
packageName: Easy Chart Lite
|
||||
packageVersion: 1.0
|
||||
assetPath: Assets/EasyChart/Docs/ManualWeb/manual-data.en.js
|
||||
uploadId: 857482
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 62df82b655a64ae47a4281ac0d20c941
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 359794
|
||||
packageName: Easy Chart Lite
|
||||
packageVersion: 1.0
|
||||
assetPath: Assets/EasyChart/Docs/ManualWeb/manual-data.js
|
||||
uploadId: 857482
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fbd69b467b17d4544aa7804b39eb12e3
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 359794
|
||||
packageName: Easy Chart Lite
|
||||
packageVersion: 1.0
|
||||
assetPath: Assets/EasyChart/Docs/ManualWeb/manual-data.zh.js
|
||||
uploadId: 857482
|
||||
@@ -0,0 +1,56 @@
|
||||
window.EASYCHART_MANUAL_NAV = {
|
||||
groups: [
|
||||
{
|
||||
key: "workflow",
|
||||
title: "概览",
|
||||
items: [
|
||||
"00_00-Index",
|
||||
"00_01-QuickStart",
|
||||
"00_02-WorkflowAndLibrary",
|
||||
"00_03-UGUIWorkflow",
|
||||
"00_04-RuntimeDataInjectionUIToolKit",
|
||||
"00_05-RuntimeDataInjectionUGUI"
|
||||
]
|
||||
},
|
||||
{
|
||||
key: "editor_ui",
|
||||
title: "编辑界面说明",
|
||||
items: [
|
||||
"01_01-EditorWorkflow",
|
||||
"01_02-LibraryPanel",
|
||||
"01_03-JsonInjectionPanel",
|
||||
"02_04-PreviewPanel",
|
||||
"02_05-InspectorPanel",
|
||||
"02_06-SeriesPanel"
|
||||
]
|
||||
},
|
||||
{
|
||||
key: "charts",
|
||||
title: "Series详细配置",
|
||||
items: [
|
||||
"03_01-LineChart",
|
||||
"03_02-BarChart",
|
||||
"03_03-ScatterChart",
|
||||
"03_04-HeatmapChart",
|
||||
"03_05-RadarChart",
|
||||
"03_06-PieChart",
|
||||
"03_07-RingChart"
|
||||
]
|
||||
},
|
||||
{
|
||||
key: "reference",
|
||||
title: "配置项参考",
|
||||
items: [
|
||||
"04_08-CommonRecipes",
|
||||
"04_09-FAQ"
|
||||
]
|
||||
},
|
||||
{
|
||||
key: "other",
|
||||
title: "其他",
|
||||
items: [
|
||||
"05_01-UpdatePlan"
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 00dc0b6f492769a45bf846ada698f726
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 359794
|
||||
packageName: Easy Chart Lite
|
||||
packageVersion: 1.0
|
||||
assetPath: Assets/EasyChart/Docs/ManualWeb/manual-nav.js
|
||||
uploadId: 857482
|
||||
@@ -0,0 +1 @@
|
||||
window.EASYCHART_MANUAL_OPEN = {chapterId: "01_02-LibraryPanel", anchor: "", at: "2026-03-18 17:29:31"};
|
||||
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 98e138ff335d55a41b8243bfe72183b7
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 359794
|
||||
packageName: Easy Chart Lite
|
||||
packageVersion: 1.0
|
||||
assetPath: Assets/EasyChart/Docs/ManualWeb/manual-open.js
|
||||
uploadId: 857482
|
||||
@@ -0,0 +1,107 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<title>Unity Easy Chart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="app">
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-header">
|
||||
<div class="sidebar-title">Unity Easy Chart</div>
|
||||
<div class="sidebar-sub" id="generatedAt"></div>
|
||||
</div>
|
||||
|
||||
<div class="sidebar-lang">
|
||||
<select id="lang" aria-label="Language">
|
||||
<option value="zh">中文</option>
|
||||
<option value="en">English</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="sidebar-search">
|
||||
<input id="search" type="text" placeholder="Search chapters..." />
|
||||
</div>
|
||||
|
||||
<nav class="nav" id="nav"></nav>
|
||||
</aside>
|
||||
|
||||
<div class="main">
|
||||
<div class="content-wrap">
|
||||
<main class="content" id="content"></main>
|
||||
<aside class="toc" id="toc"></aside>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
var q = '?t=' + Date.now();
|
||||
|
||||
function getSavedLang(){
|
||||
try{
|
||||
var v = localStorage.getItem('easychart_manual_lang_v1');
|
||||
return (v === 'en' || v === 'zh') ? v : 'zh';
|
||||
}catch(e){
|
||||
return 'zh';
|
||||
}
|
||||
}
|
||||
|
||||
function loadNavConfig(next){
|
||||
var sNav = document.createElement('script');
|
||||
sNav.src = './manual-nav.js' + q;
|
||||
sNav.onload = next;
|
||||
sNav.onerror = next;
|
||||
document.body.appendChild(sNav);
|
||||
}
|
||||
|
||||
function updateGeneratedAt(){
|
||||
var el = document.getElementById('generatedAt');
|
||||
if (!el) return;
|
||||
var data = window.EASYCHART_MANUAL || {};
|
||||
el.textContent = data.generatedAt ? ('Updated: ' + data.generatedAt) : '';
|
||||
}
|
||||
|
||||
function loadApp(){
|
||||
var sApp = document.createElement('script');
|
||||
sApp.src = './app.js' + q;
|
||||
sApp.onload = updateGeneratedAt;
|
||||
document.body.appendChild(sApp);
|
||||
}
|
||||
|
||||
function loadOpenRequest(){
|
||||
var sOpen = document.createElement('script');
|
||||
sOpen.src = './manual-open.js' + q;
|
||||
sOpen.onload = loadApp;
|
||||
sOpen.onerror = loadApp;
|
||||
document.body.appendChild(sOpen);
|
||||
}
|
||||
|
||||
function afterDataLoaded(){
|
||||
var lang = getSavedLang();
|
||||
if(lang === 'en' && window.EASYCHART_MANUAL_EN) window.EASYCHART_MANUAL = window.EASYCHART_MANUAL_EN;
|
||||
if(lang === 'zh' && window.EASYCHART_MANUAL_ZH) window.EASYCHART_MANUAL = window.EASYCHART_MANUAL_ZH;
|
||||
loadNavConfig(loadOpenRequest);
|
||||
}
|
||||
|
||||
function loadDataWithFallback(){
|
||||
var lang = getSavedLang();
|
||||
var sData = document.createElement('script');
|
||||
sData.src = './manual-data.' + lang + '.js' + q;
|
||||
sData.onload = afterDataLoaded;
|
||||
sData.onerror = function(){
|
||||
var sLegacy = document.createElement('script');
|
||||
sLegacy.src = './manual-data.js' + q;
|
||||
sLegacy.onload = afterDataLoaded;
|
||||
document.body.appendChild(sLegacy);
|
||||
};
|
||||
document.body.appendChild(sData);
|
||||
}
|
||||
|
||||
loadDataWithFallback();
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f5c23fbf94ecaff4496287594235de1c
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 359794
|
||||
packageName: Easy Chart Lite
|
||||
packageVersion: 1.0
|
||||
assetPath: Assets/EasyChart/Docs/ManualWeb/manual.html
|
||||
uploadId: 857482
|
||||
@@ -0,0 +1,221 @@
|
||||
:root{
|
||||
--bg:#202123;
|
||||
--panel:#202123;
|
||||
--sidebar:#141517;
|
||||
--panel2:#2a2b32;
|
||||
--text:#d1d5db;
|
||||
--muted:rgba(236,236,241,.72);
|
||||
--muted2:rgba(236,236,241,.55);
|
||||
--border:rgba(255,255,255,.10);
|
||||
--border2:rgba(255,255,255,.06);
|
||||
--hover:rgba(255,255,255,.06);
|
||||
--active:rgba(255,255,255,.10);
|
||||
--link:#4ea3ff;
|
||||
--accent:#10a37f;
|
||||
--code:#202123;
|
||||
--code2:rgba(255,255,255,.06);
|
||||
--title:#ffffff;
|
||||
--content-indent:1.5em;
|
||||
}
|
||||
|
||||
*{box-sizing:border-box;}
|
||||
html,body{height:100%;}
|
||||
body{
|
||||
margin:0;
|
||||
background:var(--bg);
|
||||
color:var(--text);
|
||||
font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial,'Apple Color Emoji','Segoe UI Emoji';
|
||||
text-rendering:optimizeLegibility;
|
||||
-webkit-font-smoothing:antialiased;
|
||||
-moz-osx-font-smoothing:grayscale;
|
||||
overflow:hidden;
|
||||
}
|
||||
|
||||
::selection{background:rgba(16,163,127,.28);}
|
||||
|
||||
::-webkit-scrollbar{width:10px;height:10px;}
|
||||
::-webkit-scrollbar-track{background:rgba(0,0,0,0);}
|
||||
::-webkit-scrollbar-thumb{background:rgba(255,255,255,.14);border-radius:999px;}
|
||||
::-webkit-scrollbar-thumb:hover{background:rgba(255,255,255,.20);}
|
||||
|
||||
.app{display:flex;height:100vh;min-height:0;}
|
||||
|
||||
.sidebar{
|
||||
width:320px;
|
||||
background:var(--sidebar);
|
||||
border-right:1px solid var(--border);
|
||||
display:flex;
|
||||
flex-direction:column;
|
||||
height:100vh;
|
||||
min-height:0;
|
||||
}
|
||||
|
||||
.sidebar-header{padding:14px 14px 10px 14px;}
|
||||
.sidebar-title{font-weight:650;opacity:.96;color:var(--title);}
|
||||
.sidebar-sub{margin-top:6px;font-size:12px;color:var(--muted2);}
|
||||
|
||||
.sidebar-lang{padding:0 14px 10px 14px;}
|
||||
.sidebar-lang select{
|
||||
width:100%;
|
||||
padding:10px 10px;
|
||||
border-radius:10px;
|
||||
border:1px solid var(--border);
|
||||
background:var(--panel2);
|
||||
color:var(--text);
|
||||
outline:none;
|
||||
}
|
||||
.sidebar-lang select:focus{
|
||||
border-color:rgba(16,163,127,.45);
|
||||
box-shadow:0 0 0 2px rgba(16,163,127,.16);
|
||||
}
|
||||
|
||||
.sidebar-search{padding:0 14px 12px 14px;}
|
||||
.sidebar-search input{
|
||||
width:100%;
|
||||
padding:10px 10px;
|
||||
border-radius:10px;
|
||||
border:1px solid var(--border);
|
||||
background:var(--panel2);
|
||||
color:var(--text);
|
||||
outline:none;
|
||||
}
|
||||
.sidebar-search input:focus{
|
||||
border-color:rgba(16,163,127,.45);
|
||||
box-shadow:0 0 0 2px rgba(16,163,127,.16);
|
||||
}
|
||||
|
||||
.nav{padding:6px 8px 10px 8px;overflow:auto;flex:1;min-height:0;}
|
||||
|
||||
.nav-group{margin:6px 0;}
|
||||
|
||||
.nav-group-header{
|
||||
width:100%;
|
||||
display:flex;
|
||||
align-items:center;
|
||||
gap:8px;
|
||||
padding:8px 10px;
|
||||
border-radius:10px;
|
||||
background:rgba(0,0,0,.26);
|
||||
border:0;
|
||||
color:rgba(236,236,241,1);
|
||||
cursor:pointer;
|
||||
text-align:left;
|
||||
}
|
||||
|
||||
.nav-group-header:hover{background:rgba(0,0,0,.34);color:var(--title);}
|
||||
|
||||
.nav-group-toggle{
|
||||
width:14px;
|
||||
flex:0 0 14px;
|
||||
opacity:.9;
|
||||
}
|
||||
|
||||
.nav-group-header[data-expanded="true"] .nav-group-toggle::before{content:"v";}
|
||||
.nav-group-header[data-expanded="false"] .nav-group-toggle::before{content: ">";}
|
||||
|
||||
.nav-group-title{font-size:15px;font-weight:700;letter-spacing:.2px;}
|
||||
|
||||
.nav-children{padding-left:20px;margin-top:2px;}
|
||||
|
||||
.nav-item{
|
||||
display:block;
|
||||
padding:10px 10px;
|
||||
margin:4px 0;
|
||||
border-radius:10px;
|
||||
color:var(--text);
|
||||
text-decoration:none;
|
||||
line-height:1.25;
|
||||
font-size:13px;
|
||||
opacity:.92;
|
||||
}
|
||||
.nav-item:hover{background:var(--hover);}
|
||||
.nav-item.active{background:var(--active);}
|
||||
|
||||
.main{flex:1;display:flex;justify-content:center;overflow:auto;min-height:0;}
|
||||
|
||||
.content-wrap{width:100%;max-width:1120px;display:flex;gap:18px;padding:24px 24px;min-height:0;}
|
||||
|
||||
.content{
|
||||
flex:1;
|
||||
background:transparent;
|
||||
}
|
||||
|
||||
.content > :first-child{margin-top:0;}
|
||||
|
||||
.toc{
|
||||
width:260px;
|
||||
flex:0 0 260px;
|
||||
border-left:1px solid var(--border);
|
||||
padding-left:16px;
|
||||
position:sticky;
|
||||
top:16px;
|
||||
height:calc(100vh - 48px);
|
||||
overflow:auto;
|
||||
}
|
||||
|
||||
.toc-title{font-size:12px;color:var(--muted);margin:4px 0 8px 0;}
|
||||
.toc a{display:block;color:var(--muted);text-decoration:none;padding:6px 6px;border-radius:8px;}
|
||||
.toc a:hover{background:var(--hover);color:var(--text);}
|
||||
|
||||
h1{font-size:28px;line-height:1.25;margin:0 0 18px 0;color:var(--title);}
|
||||
h2{font-size:20px;line-height:1.35;margin:30px 0 16px 0;color:var(--title);}
|
||||
h3{font-size:16px;line-height:1.35;margin:22px 0 14px 0;color:var(--title);}
|
||||
|
||||
p{margin:8px 0;color:var(--text);line-height:1.75;}
|
||||
ul,ol{margin:10px 0 10px 22px;}
|
||||
li{margin:6px 0;line-height:1.6;}
|
||||
|
||||
.content p,
|
||||
.content ul,
|
||||
.content ol,
|
||||
.content pre,
|
||||
.content blockquote,
|
||||
.content hr,
|
||||
.content .notice{
|
||||
margin-left:var(--content-indent);
|
||||
}
|
||||
|
||||
pre{
|
||||
background:var(--code);
|
||||
border:1px solid var(--border2);
|
||||
border-radius:12px;
|
||||
padding:14px;
|
||||
overflow:auto;
|
||||
line-height:1.55;
|
||||
}
|
||||
pre code{display:block;color:rgba(255,255,255,.92);}
|
||||
code{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,'Liberation Mono','Courier New',monospace;}
|
||||
|
||||
code.inline{
|
||||
background:var(--code2);
|
||||
border:1px solid var(--border2);
|
||||
padding:2px 6px;
|
||||
border-radius:8px;
|
||||
font-size:0.95em;
|
||||
}
|
||||
|
||||
blockquote{
|
||||
margin:12px 0;
|
||||
padding:10px 12px;
|
||||
border-left:3px solid rgba(16,163,127,.40);
|
||||
background:rgba(0,0,0,.10);
|
||||
border-radius:12px;
|
||||
color:var(--muted);
|
||||
}
|
||||
|
||||
a{color:var(--link);text-decoration:none;}
|
||||
a:hover{text-decoration:underline;}
|
||||
|
||||
hr{border:0;border-top:1px solid var(--border);margin:18px 0;}
|
||||
|
||||
.notice{padding:12px 14px;border:1px solid var(--border2);border-radius:12px;background:rgba(0,0,0,.10);color:var(--muted);}
|
||||
|
||||
@media (max-width: 1100px){
|
||||
.content-wrap{flex-direction:column;}
|
||||
.toc{width:auto;flex:auto;position:relative;top:auto;height:auto;border-left:none;border-top:1px solid var(--border);padding:16px 0 0 0;}
|
||||
}
|
||||
|
||||
@media (max-width: 860px){
|
||||
.sidebar{display:none;}
|
||||
.content-wrap{padding:18px 16px;}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8e280d356eedc5743aa1f34f0d4b6e63
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 359794
|
||||
packageName: Easy Chart Lite
|
||||
packageVersion: 1.0
|
||||
assetPath: Assets/EasyChart/Docs/ManualWeb/styles.css
|
||||
uploadId: 857482
|
||||
Reference in New Issue
Block a user