Add vertical resizer for voice panel

This commit is contained in:
dimitrievgs 2026-04-30 19:32:12 +03:00
parent aee60c1ac2
commit 2dd033a010
2 changed files with 89 additions and 36 deletions

View File

@ -757,11 +757,39 @@
border-top: 1px solid var(--background-modifier-border); border-top: 1px solid var(--background-modifier-border);
} }
.voice-panel-container { .voice-panel-resizer {
height: 4px;
width: 100%;
cursor: ns-resize;
background-color: var(--divider-color);
flex-shrink: 0;
z-index: 10;
}
.voice-panel-resizer:hover {
background-color: var(--interactive-accent);
}
/* Убедимся, что нижняя панель не перекрывает контент */
.voice-panel-fixed-bottom {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
min-height: 50px; /* Минимальная доступная высота */
}
.voice-panel-container {
height: 100%; height: 100%;
padding: 5px; display: flex;
flex-direction: column;
}
.voice-body {
flex: 1;
overflow-y: auto;
background-color: var(--background-primary);
border: 1px inset var(--background-modifier-border);
margin: 4px;
padding: 8px;
} }
.voice-header { .voice-header {
@ -791,16 +819,6 @@
border-bottom: 2px solid var(--text-accent); border-bottom: 2px solid var(--text-accent);
} }
.voice-body {
flex: 1;
overflow-y: auto;
font-size: 12px;
font-family: var(--font-monospace);
padding: 10px;
background-color: var(--background-primary);
white-space: pre-wrap; /* Чтобы транскрибация не уходила в одну строку */
}
/* Кнопки управления голосом */ /* Кнопки управления голосом */
.v-controls button { .v-controls button {
margin-right: 5px; margin-right: 5px;

View File

@ -91,56 +91,91 @@ export class GraphView extends ItemView {
const container = this.containerEl.children[1] as HTMLElement; const container = this.containerEl.children[1] as HTMLElement;
container.empty(); container.empty();
// 1. Основной контейнер - теперь вертикальный стек
const mainContainer = container.createDiv('llm-agent-graph-main'); const mainContainer = container.createDiv('llm-agent-graph-main');
mainContainer.style.cssText = ` mainContainer.style.cssText = `
display: flex; display: flex;
flex-direction: column; /* Элементы кладутся друг под друга */ flex-direction: column;
height: 100%; height: 100%;
width: 100%; width: 100%;
overflow: hidden; overflow: hidden;
`; `;
// 2. Верхняя часть (История + Граф) // 1. Верхняя часть
const upperContent = mainContainer.createDiv('upper-content-wrapper'); const upperContent = mainContainer.createDiv('upper-content-wrapper');
upperContent.style.cssText = ` upperContent.style.cssText = `
display: flex; display: flex;
flex-direction: row; /* Элементы бок о бок */ flex-direction: row;
flex: 1; /* Занимает всё свободное место (около 75-80%) */ flex: 1;
width: 100%; width: 100%;
min-height: 0; /* Важно для корректного скролла внутри */ min-height: 0;
`; `;
// 3. Левая панель для истории (внутри верхней части)
this.historyContainer = upperContent.createDiv('llm-agent-history-sidebar'); this.historyContainer = upperContent.createDiv('llm-agent-history-sidebar');
this.historyContainer.classList.add(this.isHistoryCollapsed ? 'collapsed' : 'expanded'); this.historyContainer.classList.add(this.isHistoryCollapsed ? 'collapsed' : 'expanded');
// 4. Правая панель для графа (внутри верхней части)
this.graphContainer = upperContent.createDiv('llm-agent-graph-container'); this.graphContainer = upperContent.createDiv('llm-agent-graph-container');
this.graphContainer.style.cssText = ` this.graphContainer.style.cssText = `flex: 1; position: relative; background-color: var(--background-primary);`;
flex: 1;
position: relative;
background-color: var(--background-primary);
`;
// 5. Контейнер для голосовой панели (строго ВНИЗУ) // 2. РАЗДЕЛИТЕЛЬ (Resizer)
const voiceContainer = mainContainer.createDiv('voice-panel-fixed-bottom'); const resizer = mainContainer.createDiv('voice-panel-resizer');
voiceContainer.style.cssText = ` resizer.style.cssText = `
height: 200px; /* Фиксированная высота или % */ height: 4px;
width: 100%; width: 100%;
border-top: 1px solid var(--divider-color); cursor: ns-resize;
background-color: var(--background-secondary); background-color: var(--divider-color);
overflow: hidden; flex-shrink: 0;
flex-shrink: 0; /* Не дает панели сжиматься */ transition: background-color 0.2s;
`; `;
// Инициализация компонентов // 3. Нижняя панель
const voiceContainer = mainContainer.createDiv('voice-panel-fixed-bottom');
let initialHeight = 150; // Высота по умолчанию
voiceContainer.style.cssText = `
height: ${initialHeight}px;
width: 100%;
background-color: var(--background-secondary);
overflow: hidden;
flex-shrink: 0;
`;
// ЛОГИКА ИЗМЕНЕНИЯ ВЫСОТЫ
let isResizing = false;
resizer.addEventListener('mousedown', (e) => {
isResizing = true;
document.body.style.cursor = 'ns-resize';
// Чтобы iframe/график не перехватывали события мыши
mainContainer.style.pointerEvents = 'none';
});
document.addEventListener('mousemove', (e) => {
if (!isResizing) return;
// Вычисляем расстояние от верха контейнера
const containerRect = mainContainer.getBoundingClientRect();
const newHeight = containerRect.bottom - e.clientY;
// Ограничения (мин 50px, макс 70% высоты)
if (newHeight > 50 && newHeight < containerRect.height * 0.7) {
voiceContainer.style.height = `${newHeight}px`;
}
});
document.addEventListener('mouseup', () => {
if (isResizing) {
isResizing = false;
document.body.style.cursor = 'default';
mainContainer.style.pointerEvents = 'all';
}
});
// Инициализация остальных компонентов
this.historyPanel = new HistoryPanel( this.historyPanel = new HistoryPanel(
this.historyContainer, this.historyContainer,
{ graphs: this.graphsList, eventBus: this.plugin.eventBus }, { graphs: this.graphsList, eventBus: this.plugin.eventBus },
this.plugin this.plugin
); );
this.addToggleButton(); this.addToggleButton();
this.addGlobalActionButtons(); this.addGlobalActionButtons();
this.initializeGraphPanel(); this.initializeGraphPanel();