mirror of
https://github.com/youfoundjk/TeXcore.git
synced 2026-07-22 07:33:31 +00:00
feat(tikz): add new circuit and flowchart components to AssetsManager; enhance library tab functionality in LeftSidebar
This commit is contained in:
parent
53def164d5
commit
67c6e83bf9
5 changed files with 137 additions and 19 deletions
|
|
@ -135,6 +135,34 @@ export class AssetsManager {
|
|||
category: 'Circuits',
|
||||
svgMarkup: `<svg viewBox="0 0 50 20" width="40" height="20" style="color: var(--text-normal);"><path d="M0,10 L10,10 Q14,3 18,10 Q22,3 26,10 Q30,3 34,10 Q38,3 40,10 L50,10" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>`,
|
||||
tikzCommand: '\\draw ({x}, {y}) to[L, l={label}] ({x2}, {y2});'
|
||||
},
|
||||
{
|
||||
name: 'Battery',
|
||||
type: 'wire',
|
||||
category: 'Circuits',
|
||||
svgMarkup: `<svg viewBox="0 0 50 20" width="40" height="20" style="color: var(--text-normal);"><line x1="0" y1="10" x2="20" y2="10" stroke="currentColor" stroke-width="2"/><line x1="20" y1="2" x2="20" y2="18" stroke="currentColor" stroke-width="2"/><line x1="24" y1="6" x2="24" y2="14" stroke="currentColor" stroke-width="3"/><line x1="28" y1="2" x2="28" y2="18" stroke="currentColor" stroke-width="2"/><line x1="32" y1="6" x2="32" y2="14" stroke="currentColor" stroke-width="3"/><line x1="32" y1="10" x2="50" y2="10" stroke="currentColor" stroke-width="2"/></svg>`,
|
||||
tikzCommand: '\\draw ({x}, {y}) to[battery2, l={label}] ({x2}, {y2});'
|
||||
},
|
||||
{
|
||||
name: 'Diode',
|
||||
type: 'wire',
|
||||
category: 'Circuits',
|
||||
svgMarkup: `<svg viewBox="0 0 50 20" width="40" height="20" style="color: var(--text-normal);"><line x1="0" y1="10" x2="20" y2="10" stroke="currentColor" stroke-width="2"/><polygon points="20,4 20,16 32,10" fill="none" stroke="currentColor" stroke-width="2"/><line x1="32" y1="4" x2="32" y2="16" stroke="currentColor" stroke-width="2"/><line x1="32" y1="10" x2="50" y2="10" stroke="currentColor" stroke-width="2"/></svg>`,
|
||||
tikzCommand: '\\draw ({x}, {y}) to[D, l={label}] ({x2}, {y2});'
|
||||
},
|
||||
{
|
||||
name: 'AC Source',
|
||||
type: 'wire',
|
||||
category: 'Circuits',
|
||||
svgMarkup: `<svg viewBox="0 0 50 20" width="40" height="20" style="color: var(--text-normal);"><line x1="0" y1="10" x2="15" y2="10" stroke="currentColor" stroke-width="2"/><circle cx="25" cy="10" r="10" fill="none" stroke="currentColor" stroke-width="2"/><path d="M 20 10 Q 22.5 5 25 10 T 30 10" fill="none" stroke="currentColor" stroke-width="2"/><line x1="35" y1="10" x2="50" y2="10" stroke="currentColor" stroke-width="2"/></svg>`,
|
||||
tikzCommand: '\\draw ({x}, {y}) to[vsourcesin, l={label}] ({x2}, {y2});'
|
||||
},
|
||||
{
|
||||
name: 'Ground',
|
||||
type: 'component',
|
||||
category: 'Circuits',
|
||||
svgMarkup: `<svg viewBox="0 0 40 40" width="30" height="30" style="color: var(--text-normal);"><line x1="20" y1="5" x2="20" y2="25" stroke="currentColor" stroke-width="2"/><line x1="10" y1="25" x2="30" y2="25" stroke="currentColor" stroke-width="2"/><line x1="13" y1="29" x2="27" y2="29" stroke="currentColor" stroke-width="2"/><line x1="17" y1="33" x2="23" y2="33" stroke="currentColor" stroke-width="2"/></svg>`,
|
||||
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: `<svg viewBox="0 0 50 30" width="40" height="25" style="color: var(--text-normal);"><rect x="5" y="5" width="40" height="20" rx="10" ry="10" fill="none" stroke="currentColor" stroke-width="2"/></svg>`,
|
||||
tikzCommand: '\\node[draw, rounded corners=10pt] at ({x}, {y}) (start1) {{label}};'
|
||||
},
|
||||
{
|
||||
name: 'Process',
|
||||
type: 'component',
|
||||
category: 'Flowcharts',
|
||||
svgMarkup: `<svg viewBox="0 0 50 30" width="40" height="25" style="color: var(--text-normal);"><rect x="5" y="5" width="40" height="20" fill="none" stroke="currentColor" stroke-width="2"/></svg>`,
|
||||
tikzCommand: '\\node[draw, minimum width=1.5cm, minimum height=0.8cm] at ({x}, {y}) (proc1) {{label}};'
|
||||
},
|
||||
{
|
||||
name: 'Decision',
|
||||
type: 'component',
|
||||
category: 'Flowcharts',
|
||||
svgMarkup: `<svg viewBox="0 0 50 30" width="40" height="25" style="color: var(--text-normal);"><polygon points="25,3 45,15 25,27 5,15" fill="none" stroke="currentColor" stroke-width="2"/></svg>`,
|
||||
tikzCommand: '\\node[draw, diamond, aspect=1.5] at ({x}, {y}) (dec1) {{label}};'
|
||||
},
|
||||
{
|
||||
name: 'Input/Output',
|
||||
type: 'component',
|
||||
category: 'Flowcharts',
|
||||
svgMarkup: `<svg viewBox="0 0 50 30" width="40" height="25" style="color: var(--text-normal);"><polygon points="10,5 45,5 40,25 5,25" fill="none" stroke="currentColor" stroke-width="2"/></svg>`,
|
||||
tikzCommand: '\\node[draw, trapezium, trapezium left angle=70, trapezium right angle=110] at ({x}, {y}) (io1) {{label}};'
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -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<string, ComponentTemplate[]>();
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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<PluginSettings> = {
|
|||
|
||||
// TikZJax Settings
|
||||
enableTikzjax: true,
|
||||
invertColorsInDarkMode: true
|
||||
invertColorsInDarkMode: true,
|
||||
pinnedTikzComponents: []
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in a new issue