diff --git a/src/features/tikz-editor/assets-manager.ts b/src/features/tikz-editor/assets-manager.ts
index 9fdb06d..041dd68 100644
--- a/src/features/tikz-editor/assets-manager.ts
+++ b/src/features/tikz-editor/assets-manager.ts
@@ -135,6 +135,34 @@ export class AssetsManager {
category: 'Circuits',
svgMarkup: ``,
tikzCommand: '\\draw ({x}, {y}) to[L, l={label}] ({x2}, {y2});'
+ },
+ {
+ name: 'Battery',
+ type: 'wire',
+ category: 'Circuits',
+ svgMarkup: ``,
+ tikzCommand: '\\draw ({x}, {y}) to[battery2, l={label}] ({x2}, {y2});'
+ },
+ {
+ name: 'Diode',
+ type: 'wire',
+ category: 'Circuits',
+ svgMarkup: ``,
+ tikzCommand: '\\draw ({x}, {y}) to[D, l={label}] ({x2}, {y2});'
+ },
+ {
+ name: 'AC Source',
+ type: 'wire',
+ category: 'Circuits',
+ svgMarkup: ``,
+ tikzCommand: '\\draw ({x}, {y}) to[vsourcesin, l={label}] ({x2}, {y2});'
+ },
+ {
+ name: 'Ground',
+ type: 'component',
+ category: 'Circuits',
+ svgMarkup: ``,
+ tikzCommand: '\\draw ({x}, {y}) node[ground] {{{label}}};'
}
]
},
@@ -167,6 +195,41 @@ export class AssetsManager {
tikzCommand: '\\node[not gate US, draw] at ({x}, {y}) (not1) {{label}};'
}
]
+ },
+ {
+ name: 'tikz-flowchart',
+ displayName: 'Flowcharts',
+ installed: false,
+ components: [
+ {
+ name: 'Start/End',
+ type: 'component',
+ category: 'Flowcharts',
+ svgMarkup: ``,
+ tikzCommand: '\\node[draw, rounded corners=10pt] at ({x}, {y}) (start1) {{label}};'
+ },
+ {
+ name: 'Process',
+ type: 'component',
+ category: 'Flowcharts',
+ svgMarkup: ``,
+ tikzCommand: '\\node[draw, minimum width=1.5cm, minimum height=0.8cm] at ({x}, {y}) (proc1) {{label}};'
+ },
+ {
+ name: 'Decision',
+ type: 'component',
+ category: 'Flowcharts',
+ svgMarkup: ``,
+ tikzCommand: '\\node[draw, diamond, aspect=1.5] at ({x}, {y}) (dec1) {{label}};'
+ },
+ {
+ name: 'Input/Output',
+ type: 'component',
+ category: 'Flowcharts',
+ svgMarkup: ``,
+ tikzCommand: '\\node[draw, trapezium, trapezium left angle=70, trapezium right angle=110] at ({x}, {y}) (io1) {{label}};'
+ }
+ ]
}
];
diff --git a/src/features/tikz-editor/components/left-sidebar.ts b/src/features/tikz-editor/components/left-sidebar.ts
index 2567781..1e8fa6f 100644
--- a/src/features/tikz-editor/components/left-sidebar.ts
+++ b/src/features/tikz-editor/components/left-sidebar.ts
@@ -2,6 +2,8 @@ import { type TikzEditorContext, type ComponentTemplate } from '../types';
import { AssetsManager } from '../assets-manager';
export class LeftSidebar {
+ private activeLibraryTab: 'basic' | 'all' = 'basic';
+
constructor(
private context: TikzEditorContext,
private containerEl: HTMLElement
@@ -126,6 +128,33 @@ export class LeftSidebar {
this.renderLibraryList();
};
+ // 2.5 Library Tabs
+ const tabsContainer = this.containerEl.createDiv({ cls: 'library-tabs' });
+ const basicTabBtn = tabsContainer.createEl('button', {
+ cls: `tab-btn${this.activeLibraryTab === 'basic' ? ' active' : ''}`,
+ text: 'Basic'
+ });
+ const allTabBtn = tabsContainer.createEl('button', {
+ cls: `tab-btn${this.activeLibraryTab === 'all' ? ' active' : ''}`,
+ text: 'All'
+ });
+
+ basicTabBtn.onclick = () => {
+ if (this.activeLibraryTab === 'basic') return;
+ this.activeLibraryTab = 'basic';
+ basicTabBtn.addClass('active');
+ allTabBtn.removeClass('active');
+ this.renderLibraryList();
+ };
+
+ allTabBtn.onclick = () => {
+ if (this.activeLibraryTab === 'all') return;
+ this.activeLibraryTab = 'all';
+ allTabBtn.addClass('active');
+ basicTabBtn.removeClass('active');
+ this.renderLibraryList();
+ };
+
// 3. Component Library List Container
this.containerEl.createDiv({ cls: 'library' });
this.renderLibraryList();
@@ -209,7 +238,9 @@ export class LeftSidebar {
// Category components builder
const core = AssetsManager.getCoreComponents();
- const extra = this.context.getPackages().flatMap(p => p.components);
+ const extra = this.context.getPackages()
+ .filter(p => p.installed)
+ .flatMap(p => p.components);
const all = [...core, ...extra];
const pinnedComponents = this.context.getPinnedComponents();
@@ -218,26 +249,44 @@ export class LeftSidebar {
);
const basic = [...core, ...pinned];
- // Filter by query
- const searchQuery = this.context.getSearchQuery();
- let filtered = all;
- if (searchQuery.trim()) {
- filtered = all.filter(
- c =>
- c.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
- c.category.toLowerCase().includes(searchQuery.toLowerCase())
- );
- }
+ const searchQuery = this.context.getSearchQuery().trim().toLowerCase();
const categoriesMap = new Map();
- if (!searchQuery.trim()) {
- categoriesMap.set('Basic', basic);
+
+ if (this.activeLibraryTab === 'basic') {
+ // Basic Tab: Show commonly used (basic) components, optionally filtered by search
+ const filteredBasic = searchQuery
+ ? basic.filter(
+ c =>
+ c.name.toLowerCase().includes(searchQuery) ||
+ c.category.toLowerCase().includes(searchQuery)
+ )
+ : basic;
+
+ if (filteredBasic.length > 0) {
+ categoriesMap.set('Basic', filteredBasic);
+ }
} else {
- filtered.forEach(c => {
- if (!categoriesMap.has(c.category)) {
- categoriesMap.set(c.category, []);
+ // All Tab: Show all components grouped by their categories
+ const filteredAll = searchQuery
+ ? all.filter(
+ c =>
+ c.name.toLowerCase().includes(searchQuery) ||
+ c.category.toLowerCase().includes(searchQuery)
+ )
+ : all;
+
+ filteredAll.forEach(c => {
+ // Core components are displayed under 'Basic'
+ const category = core.some(coreComp => coreComp.name === c.name) ? 'Basic' : c.category;
+
+ if (!categoriesMap.has(category)) {
+ categoriesMap.set(category, []);
+ }
+ const catList = categoriesMap.get(category);
+ if (catList && !catList.some(comp => comp.name === c.name)) {
+ catList.push(c);
}
- categoriesMap.get(c.category)?.push(c);
});
}
diff --git a/src/features/tikz-editor/tikz-editor-modal.ts b/src/features/tikz-editor/tikz-editor-modal.ts
index 2d11dc9..efdcff6 100644
--- a/src/features/tikz-editor/tikz-editor-modal.ts
+++ b/src/features/tikz-editor/tikz-editor-modal.ts
@@ -82,6 +82,7 @@ export class TikzEditorModal extends Modal implements TikzEditorContext {
private onSaveCallback?: (newSource: string) => void
) {
super(app);
+ this.pinnedComponents = this.plugin.settings.pinnedTikzComponents || [];
this.codec = new TikzCodec(
x => this.toCanvasX(x),
y => this.toCanvasY(y),
@@ -149,6 +150,8 @@ export class TikzEditorModal extends Modal implements TikzEditorContext {
}
setPinnedComponents(pinned: string[]) {
this.pinnedComponents = pinned;
+ this.plugin.settings.pinnedTikzComponents = pinned;
+ void this.plugin.saveSettings();
}
getActiveTab() {
return this.activeTab;
diff --git a/src/settings/settings.ts b/src/settings/settings.ts
index d2c4b4b..b64d56f 100644
--- a/src/settings/settings.ts
+++ b/src/settings/settings.ts
@@ -77,6 +77,7 @@ export interface PluginSettings {
// TikZJax Settings
enableTikzjax: boolean;
invertColorsInDarkMode: boolean;
+ pinnedTikzComponents?: string[];
// Version tracking
currentVersion: string | null;
@@ -155,5 +156,6 @@ export const DEFAULT_SETTINGS: Required = {
// TikZJax Settings
enableTikzjax: true,
- invertColorsInDarkMode: true
+ invertColorsInDarkMode: true,
+ pinnedTikzComponents: []
};
diff --git a/src/styles/main.css b/src/styles/main.css
index 2d1f12f..30386d6 100644
--- a/src/styles/main.css
+++ b/src/styles/main.css
@@ -1290,7 +1290,8 @@ div.tikz-editor-modal .modal-close-button {
flex-shrink: 0;
}
-.tikz-editor-ui .tabs-header {
+.tikz-editor-ui .tabs-header,
+.tikz-editor-ui .library-tabs {
display: flex;
border-bottom: 1px solid var(--background-modifier-border);
background-color: var(--background-secondary);