@@ -7552,7 +7640,7 @@ document.addEventListener("DOMContentLoaded", async function () {
if (previewCode) previewCode.value = t.code.trim();
confirmBtn.disabled = false;
- const catClass = t.category.toLowerCase().replace(/\s+/g, '');
+ const catClass = t.category.toLowerCase().replace(/[^a-z0-9]+/g, '');
// Render bottom preview container with API image & fallback
previewContainer.innerHTML = `
diff --git a/desktop-app/resources/styles.css b/desktop-app/resources/styles.css
index 20fff841..72391f1c 100644
--- a/desktop-app/resources/styles.css
+++ b/desktop-app/resources/styles.css
@@ -5366,39 +5366,114 @@ html[data-theme="dark"] .d2-diagram > svg:not([data-diagram-native-dark="true"])
}
.diagram-modal-sidebar {
- width: 220px;
- border-right: 1px solid var(--border-color);
- padding: 16px 8px;
+ width: 260px;
+ margin: 16px 0 16px 16px;
+ border: 1px solid var(--border-color);
+ border-radius: 8px;
+ background: var(--bg-color);
+ padding: 0;
overflow-y: auto;
display: flex;
flex-direction: column;
- gap: 4px;
+ gap: 0;
flex-shrink: 0;
}
-.diagram-sidebar-btn {
+.diagram-sidebar-group {
display: flex;
- align-items: center;
- gap: 10px;
- padding: 10px 14px;
+ flex-direction: column;
+ border-top: 1px solid var(--border-color);
+}
+
+.diagram-sidebar-group:first-child {
+ border-top: none;
+}
+
+.diagram-sidebar-group-header,
+.diagram-sidebar-btn {
+ width: 100%;
border: none;
background: transparent;
color: var(--text-color);
- text-align: left;
- border-radius: 6px;
cursor: pointer;
- font-size: 0.9rem;
- font-weight: 500;
+ font-size: 0.95rem;
+ text-align: left;
transition: background-color 0.15s ease, color 0.15s ease;
}
+.diagram-sidebar-group-header {
+ display: grid;
+ grid-template-columns: 24px 1fr 18px;
+ align-items: center;
+ gap: 12px;
+ min-height: 62px;
+ padding: 0 18px;
+ font-weight: 500;
+}
+
+.diagram-sidebar-group-header:hover {
+ background-color: var(--button-hover-bg, rgba(120, 120, 120, 0.06));
+}
+
+.diagram-sidebar-group-icon,
+.diagram-sidebar-item-icon,
+.diagram-sidebar-chevron {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ line-height: 1;
+}
+
+.diagram-sidebar-group-icon {
+ color: var(--text-color);
+ font-size: 1.1rem;
+}
+
+.diagram-sidebar-chevron {
+ justify-self: end;
+ color: var(--text-muted, #6b7280);
+ font-size: 0.85rem;
+}
+
+.diagram-sidebar-items {
+ display: none;
+ flex-direction: column;
+ gap: 4px;
+ padding: 0 12px 12px;
+}
+
+.diagram-sidebar-group.is-expanded .diagram-sidebar-items {
+ display: flex;
+}
+
+.diagram-sidebar-btn {
+ display: flex;
+ align-items: center;
+ gap: 14px;
+ min-height: 50px;
+ padding: 0 16px 0 20px;
+ border-radius: 7px;
+ font-weight: 500;
+}
+
.diagram-sidebar-btn:hover {
- background-color: var(--button-hover-bg, rgba(120, 120, 120, 0.1));
+ background-color: var(--button-hover-bg, rgba(120, 120, 120, 0.06));
}
.diagram-sidebar-btn.is-active {
- background-color: var(--accent-color, #0076ff);
- color: #fff;
+ background-color: color-mix(in srgb, var(--accent-color, #0076ff) 13%, transparent);
+ color: var(--accent-color, #0076ff);
+ font-weight: 650;
+}
+
+.diagram-sidebar-btn.is-active .diagram-sidebar-item-icon {
+ color: var(--accent-color, #0076ff);
+}
+
+.diagram-sidebar-item-icon {
+ width: 22px;
+ color: var(--text-muted, #6b7280);
+ font-size: 1.05rem;
}
.diagram-modal-content {
@@ -5646,18 +5721,42 @@ html[data-theme="dark"] .diagram-preview-container {
display: none !important;
}
-@media (max-width: 768px) {
+@media (max-width: 640px) {
.diagram-modal-body {
flex-direction: column;
}
.diagram-modal-sidebar {
width: 100%;
height: 60px;
+ margin: 0;
flex-direction: row;
border-right: none;
border-bottom: 1px solid var(--border-color);
+ border-left: none;
+ border-radius: 0;
padding: 8px;
+ gap: 6px;
}
+
+ .diagram-sidebar-group-header {
+ display: none;
+ }
+
+ .diagram-sidebar-group {
+ display: contents;
+ }
+
+ .diagram-sidebar-items {
+ display: contents;
+ }
+
+ .diagram-sidebar-btn {
+ width: auto;
+ min-height: 36px;
+ flex-shrink: 0;
+ padding: 0 12px;
+ }
+
.diagram-modal-box {
height: 95vh;
}
diff --git a/script.js b/script.js
index 00801071..82a110fd 100644
--- a/script.js
+++ b/script.js
@@ -6836,7 +6836,8 @@ ${selector} .arrowheadPath {
WaveDrom: 'wavedrom',
Markmap: 'markmap',
Mermaid: 'mermaid',
- 'ABC Notation': 'abc'
+ 'ABC Notation': 'abc',
+ 'STL (3D)': 'stl'
};
return engines[category] || null;
}
@@ -6938,7 +6939,7 @@ ${selector} .arrowheadPath {
const cleanCode = getCleanCode(template.code);
const engine = getDiagramEngineForCategory(template.category);
try {
- if (template.category === 'ABC Notation') {
+ if (template.category === 'ABC Notation' || template.category === 'STL (3D)') {
callback(null);
return;
}
@@ -6998,16 +6999,45 @@ ${selector} .arrowheadPath {
if (previewCode) previewCode.value = '';
confirmBtn.disabled = true;
- const categories = [
- 'Mermaid',
- 'PlantUML',
- 'Graphviz',
- 'D2',
- 'Vega-Lite',
- 'ABC Notation',
- 'WaveDrom',
- 'Markmap'
+ const categoryGroups = [
+ {
+ label: 'Diagrams',
+ icon: 'bi-diagram-3',
+ categories: ['Mermaid', 'PlantUML', 'Graphviz', 'D2']
+ },
+ {
+ label: 'Mind Maps',
+ icon: 'bi-diagram-2',
+ categories: ['Markmap']
+ },
+ {
+ label: 'Data Visualization',
+ icon: 'bi-bar-chart-line',
+ categories: ['Vega-Lite']
+ },
+ {
+ label: 'Technical Notation',
+ icon: 'bi-code-slash',
+ categories: ['WaveDrom', 'ABC Notation']
+ },
+ {
+ label: '3D Models',
+ icon: 'bi-box',
+ categories: ['STL (3D)']
+ }
];
+
+ const categoryIcons = {
+ Mermaid: 'bi-water',
+ PlantUML: 'bi-leaf',
+ Graphviz: 'bi-bezier2',
+ D2: 'bi-badge-2d',
+ Markmap: 'bi-diagram-2',
+ 'Vega-Lite': 'bi-bar-chart-line',
+ WaveDrom: 'bi-activity',
+ 'ABC Notation': 'bi-music-note-beamed',
+ 'STL (3D)': 'bi-box'
+ };
const svgFlowchart = `
`;
const svgMermaidFlowchartLR = `
`;
@@ -7119,6 +7149,10 @@ ${selector} .arrowheadPath {
const svgMarkmapChecklist = `
`;
const svgMarkmapCode = `
`;
+ // STL (3D) local previews
+ const svgStlTetrahedron = `
`;
+ const svgStlCube = `
`;
+
const templates = [
// Mermaid
{
@@ -7702,6 +7736,24 @@ ${selector} .arrowheadPath {
label: 'Inline Code Blocks',
svg: svgMarkmapCode,
code: '```markmap\n# Development\n## Languages\n- `JavaScript`\n- `Python`\n## Functions\n- `main()`\n- `helper_func()`\n```\n'
+ },
+
+ // STL (3D)
+ {
+ id: 'stl-tetrahedron',
+ category: 'STL (3D)',
+ title: 'Tetrahedron Mesh',
+ label: 'Tetrahedron Mesh',
+ svg: svgStlTetrahedron,
+ code: '```stl\nsolid tetrahedron\n facet normal 0 0 1\n outer loop\n vertex 0 0 0\n vertex 1 0 0\n vertex 0 1 0\n endloop\n endfacet\n facet normal 0 1 0\n outer loop\n vertex 0 0 0\n vertex 0 0 1\n vertex 1 0 0\n endloop\n endfacet\n facet normal 1 0 0\n outer loop\n vertex 0 0 0\n vertex 0 1 0\n vertex 0 0 1\n endloop\n endfacet\n facet normal 1 1 1\n outer loop\n vertex 1 0 0\n vertex 0 0 1\n vertex 0 1 0\n endloop\n endfacet\nendsolid tetrahedron\n```\n'
+ },
+ {
+ id: 'stl-calibration-cube',
+ category: 'STL (3D)',
+ title: 'Calibration Cube',
+ label: 'Calibration Cube',
+ svg: svgStlCube,
+ code: '```stl\nsolid calibration_cube_20mm\n facet normal 0 0 -1\n outer loop\n vertex 0 0 0\n vertex 20 0 0\n vertex 20 20 0\n endloop\n endfacet\n facet normal 0 0 -1\n outer loop\n vertex 0 0 0\n vertex 20 20 0\n vertex 0 20 0\n endloop\n endfacet\n facet normal 0 0 1\n outer loop\n vertex 0 0 20\n vertex 20 20 20\n vertex 20 0 20\n endloop\n endfacet\n facet normal 0 0 1\n outer loop\n vertex 0 0 20\n vertex 0 20 20\n vertex 20 20 20\n endloop\n endfacet\n facet normal 0 -1 0\n outer loop\n vertex 0 0 0\n vertex 0 0 20\n vertex 20 0 20\n endloop\n endfacet\n facet normal 0 -1 0\n outer loop\n vertex 0 0 0\n vertex 20 0 20\n vertex 20 0 0\n endloop\n endfacet\n facet normal 1 0 0\n outer loop\n vertex 20 0 0\n vertex 20 0 20\n vertex 20 20 20\n endloop\n endfacet\n facet normal 1 0 0\n outer loop\n vertex 20 0 0\n vertex 20 20 20\n vertex 20 20 0\n endloop\n endfacet\n facet normal 0 1 0\n outer loop\n vertex 20 20 0\n vertex 20 20 20\n vertex 0 20 20\n endloop\n endfacet\n facet normal 0 1 0\n outer loop\n vertex 20 20 0\n vertex 0 20 20\n vertex 0 20 0\n endloop\n endfacet\n facet normal -1 0 0\n outer loop\n vertex 0 20 0\n vertex 0 20 20\n vertex 0 0 20\n endloop\n endfacet\n facet normal -1 0 0\n outer loop\n vertex 0 20 0\n vertex 0 0 20\n vertex 0 0 0\n endloop\n endfacet\nendsolid calibration_cube_20mm\n```\n'
}
];
@@ -7710,18 +7762,54 @@ ${selector} .arrowheadPath {
function renderSidebar() {
sidebar.textContent = '';
- categories.forEach(cat => {
- const btn = document.createElement('button');
- btn.type = 'button';
- btn.className = 'diagram-sidebar-btn';
- if (cat === activeCategory) btn.classList.add('is-active');
- btn.textContent = cat;
- btn.addEventListener('click', () => {
- activeCategory = cat;
- renderSidebar();
- renderGrid();
+ categoryGroups.forEach(group => {
+ const isExpanded = group.categories.includes(activeCategory);
+ const groupEl = document.createElement('div');
+ groupEl.className = 'diagram-sidebar-group';
+ if (isExpanded) groupEl.classList.add('is-expanded');
+
+ const heading = document.createElement('button');
+ heading.type = 'button';
+ heading.className = 'diagram-sidebar-group-header';
+ heading.setAttribute('aria-expanded', String(isExpanded));
+ heading.innerHTML = `
+
+
${group.label}
+
+ `;
+ heading.addEventListener('click', () => {
+ if (!isExpanded) {
+ activeCategory = group.categories[0];
+ selectedTemplate = null;
+ renderSidebar();
+ renderGrid();
+ }
+ });
+ groupEl.appendChild(heading);
+
+ const itemsEl = document.createElement('div');
+ itemsEl.className = 'diagram-sidebar-items';
+
+ group.categories.forEach(cat => {
+ const btn = document.createElement('button');
+ btn.type = 'button';
+ btn.className = 'diagram-sidebar-btn';
+ if (cat === activeCategory) btn.classList.add('is-active');
+ btn.innerHTML = `
+
+
${cat}
+ `;
+ btn.addEventListener('click', () => {
+ activeCategory = cat;
+ renderSidebar();
+ renderGrid();
+ });
+ itemsEl.appendChild(btn);
});
- sidebar.appendChild(btn);
+
+ groupEl.appendChild(itemsEl);
+
+ sidebar.appendChild(groupEl);
});
}
@@ -7754,7 +7842,7 @@ ${selector} .arrowheadPath {
const previewDiv = document.createElement('div');
previewDiv.className = 'diagram-card-preview';
- const catClass = t.category.toLowerCase().replace(/\s+/g, '');
+ const catClass = t.category.toLowerCase().replace(/[^a-z0-9]+/g, '');
previewDiv.innerHTML = `
@@ -7792,7 +7880,7 @@ ${selector} .arrowheadPath {
if (previewCode) previewCode.value = t.code.trim();
confirmBtn.disabled = false;
- const catClass = t.category.toLowerCase().replace(/\s+/g, '');
+ const catClass = t.category.toLowerCase().replace(/[^a-z0-9]+/g, '');
// Render bottom preview container with API image & fallback
previewContainer.innerHTML = `
diff --git a/styles.css b/styles.css
index d32280ac..5c11af99 100644
--- a/styles.css
+++ b/styles.css
@@ -5454,39 +5454,114 @@ html[data-theme="dark"] .d2-diagram>svg:not([data-diagram-native-dark="true"]) {
}
.diagram-modal-sidebar {
- width: 220px;
- border-right: 1px solid var(--border-color);
- padding: 16px 8px;
+ width: 260px;
+ margin: 16px 0 16px 16px;
+ border: 1px solid var(--border-color);
+ border-radius: 8px;
+ background: var(--bg-color);
+ padding: 0;
overflow-y: auto;
display: flex;
flex-direction: column;
- gap: 4px;
+ gap: 0;
flex-shrink: 0;
}
-.diagram-sidebar-btn {
+.diagram-sidebar-group {
display: flex;
- align-items: center;
- gap: 10px;
- padding: 10px 14px;
+ flex-direction: column;
+ border-top: 1px solid var(--border-color);
+}
+
+.diagram-sidebar-group:first-child {
+ border-top: none;
+}
+
+.diagram-sidebar-group-header,
+.diagram-sidebar-btn {
+ width: 100%;
border: none;
background: transparent;
color: var(--text-color);
- text-align: left;
- border-radius: 6px;
cursor: pointer;
- font-size: 0.9rem;
- font-weight: 500;
+ font-size: 0.95rem;
+ text-align: left;
transition: background-color 0.15s ease, color 0.15s ease;
}
+.diagram-sidebar-group-header {
+ display: grid;
+ grid-template-columns: 24px 1fr 18px;
+ align-items: center;
+ gap: 12px;
+ min-height: 62px;
+ padding: 0 18px;
+ font-weight: 500;
+}
+
+.diagram-sidebar-group-header:hover {
+ background-color: var(--button-hover-bg, rgba(120, 120, 120, 0.06));
+}
+
+.diagram-sidebar-group-icon,
+.diagram-sidebar-item-icon,
+.diagram-sidebar-chevron {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ line-height: 1;
+}
+
+.diagram-sidebar-group-icon {
+ color: var(--text-color);
+ font-size: 1.1rem;
+}
+
+.diagram-sidebar-chevron {
+ justify-self: end;
+ color: var(--text-muted, #6b7280);
+ font-size: 0.85rem;
+}
+
+.diagram-sidebar-items {
+ display: none;
+ flex-direction: column;
+ gap: 4px;
+ padding: 0 12px 12px;
+}
+
+.diagram-sidebar-group.is-expanded .diagram-sidebar-items {
+ display: flex;
+}
+
+.diagram-sidebar-btn {
+ display: flex;
+ align-items: center;
+ gap: 14px;
+ min-height: 50px;
+ padding: 0 16px 0 20px;
+ border-radius: 7px;
+ font-weight: 500;
+}
+
.diagram-sidebar-btn:hover {
- background-color: var(--button-hover-bg, rgba(120, 120, 120, 0.1));
+ background-color: var(--button-hover-bg, rgba(120, 120, 120, 0.06));
}
.diagram-sidebar-btn.is-active {
- background-color: var(--accent-color, #0076ff);
- color: #fff;
+ background-color: color-mix(in srgb, var(--accent-color, #0076ff) 13%, transparent);
+ color: var(--accent-color, #0076ff);
+ font-weight: 650;
+}
+
+.diagram-sidebar-btn.is-active .diagram-sidebar-item-icon {
+ color: var(--accent-color, #0076ff);
+}
+
+.diagram-sidebar-item-icon {
+ width: 22px;
+ color: var(--text-muted, #6b7280);
+ font-size: 1.05rem;
}
.diagram-modal-content {
@@ -5734,7 +5809,7 @@ html[data-theme="dark"] .diagram-preview-container {
display: none !important;
}
-@media (max-width: 768px) {
+@media (max-width: 640px) {
.diagram-modal-body {
flex-direction: column;
}
@@ -5742,10 +5817,33 @@ html[data-theme="dark"] .diagram-preview-container {
.diagram-modal-sidebar {
width: 100%;
height: 60px;
+ margin: 0;
flex-direction: row;
border-right: none;
border-bottom: 1px solid var(--border-color);
+ border-left: none;
+ border-radius: 0;
padding: 8px;
+ gap: 6px;
+ }
+
+ .diagram-sidebar-group-header {
+ display: none;
+ }
+
+ .diagram-sidebar-group {
+ display: contents;
+ }
+
+ .diagram-sidebar-items {
+ display: contents;
+ }
+
+ .diagram-sidebar-btn {
+ width: auto;
+ min-height: 36px;
+ flex-shrink: 0;
+ padding: 0 12px;
}
.diagram-modal-box {