mirror of
https://github.com/bitsofchris/openaugi-obsidian-plugin.git
synced 2026-07-22 12:40:27 +00:00
better UX - processing status, open when done
This commit is contained in:
parent
5fd9802300
commit
d73a5b6859
2 changed files with 168 additions and 1 deletions
45
src/main.ts
45
src/main.ts
|
|
@ -1,13 +1,16 @@
|
|||
import { Plugin, Notice, TFile } from 'obsidian';
|
||||
import { Plugin, Notice, TFile, WorkspaceLeaf } from 'obsidian';
|
||||
import { OpenAugiSettings, DEFAULT_SETTINGS } from './types/settings';
|
||||
import { OpenAIService } from './services/openai-service';
|
||||
import { FileService } from './services/file-service';
|
||||
import { OpenAugiSettingTab } from './ui/settings-tab';
|
||||
import { LoadingIndicator } from './ui/loading-indicator';
|
||||
import { sanitizeFilename } from './utils/filename-utils';
|
||||
|
||||
export default class OpenAugiPlugin extends Plugin {
|
||||
settings: OpenAugiSettings;
|
||||
openAIService: OpenAIService;
|
||||
fileService: FileService;
|
||||
loadingIndicator: LoadingIndicator;
|
||||
|
||||
async onload() {
|
||||
// Load settings
|
||||
|
|
@ -16,6 +19,14 @@ export default class OpenAugiPlugin extends Plugin {
|
|||
// Initialize services
|
||||
this.initializeServices();
|
||||
|
||||
// Initialize loading indicator
|
||||
this.app.workspace.onLayoutReady(() => {
|
||||
const statusBar = this.addStatusBarItem();
|
||||
if (statusBar.parentElement) {
|
||||
this.loadingIndicator = new LoadingIndicator(statusBar.parentElement);
|
||||
}
|
||||
});
|
||||
|
||||
// Add command to manually parse a transcript file
|
||||
this.addCommand({
|
||||
id: 'parse-transcript',
|
||||
|
|
@ -46,16 +57,36 @@ export default class OpenAugiPlugin extends Plugin {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a file in a new tab
|
||||
* @param filePath The path to the file to open
|
||||
*/
|
||||
private async openFileInNewTab(filePath: string): Promise<void> {
|
||||
const file = this.app.vault.getAbstractFileByPath(filePath);
|
||||
if (!file || !(file instanceof TFile)) {
|
||||
console.error(`File not found: ${filePath}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const leaf = this.app.workspace.getLeaf('tab');
|
||||
await leaf.openFile(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a transcript file
|
||||
* @param file The file to process
|
||||
*/
|
||||
private async processTranscriptFile(file: TFile): Promise<void> {
|
||||
try {
|
||||
// Show loading indicator
|
||||
this.loadingIndicator?.show('Processing voice transcript');
|
||||
|
||||
// Read file content
|
||||
const content = await this.app.vault.read(file);
|
||||
|
||||
// Check if API key is set
|
||||
if (!this.settings.apiKey) {
|
||||
this.loadingIndicator?.hide();
|
||||
new Notice('Please set your OpenAI API key in the plugin settings');
|
||||
return;
|
||||
}
|
||||
|
|
@ -69,8 +100,20 @@ export default class OpenAugiPlugin extends Plugin {
|
|||
// Write result to files
|
||||
await this.fileService.writeTranscriptFiles(file.basename, parsedData);
|
||||
|
||||
// Hide loading indicator
|
||||
this.loadingIndicator?.hide();
|
||||
|
||||
// Show success message
|
||||
new Notice(`Successfully parsed transcript: ${file.basename}`);
|
||||
|
||||
// Open the summary file in a new tab
|
||||
const sanitizedFilename = sanitizeFilename(file.basename);
|
||||
const summaryPath = `${this.settings.summaryFolder}/${sanitizedFilename} - summary.md`;
|
||||
await this.openFileInNewTab(summaryPath);
|
||||
} catch (error) {
|
||||
// Hide loading indicator
|
||||
this.loadingIndicator?.hide();
|
||||
|
||||
console.error('Failed to parse transcript:', error);
|
||||
new Notice('Failed to parse transcript. Check console for details.');
|
||||
}
|
||||
|
|
|
|||
124
src/ui/loading-indicator.ts
Normal file
124
src/ui/loading-indicator.ts
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
import { WorkspaceLeaf } from 'obsidian';
|
||||
|
||||
/**
|
||||
* Modal loading indicator that shows processing status
|
||||
*/
|
||||
export class LoadingIndicator {
|
||||
private statusBarItem: HTMLElement | null = null;
|
||||
private loadingContainer: HTMLElement | null = null;
|
||||
private dotElements: HTMLElement[] = [];
|
||||
private animationInterval: number | null = null;
|
||||
private statusBar: HTMLElement;
|
||||
|
||||
constructor(statusBar: HTMLElement) {
|
||||
this.statusBar = statusBar;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the loading indicator with a message
|
||||
* @param message The message to display
|
||||
*/
|
||||
show(message: string): void {
|
||||
this.hide(); // Clear any existing indicators first
|
||||
|
||||
// Create status bar item
|
||||
this.statusBarItem = this.statusBar.createEl('div', {
|
||||
cls: 'status-bar-item mod-clickable',
|
||||
attr: {
|
||||
id: 'openaugi-status',
|
||||
style: 'display: flex; align-items: center; gap: 8px; color: var(--text-accent);'
|
||||
}
|
||||
});
|
||||
|
||||
// Create icon
|
||||
const iconEl = this.statusBarItem.createEl('span', {
|
||||
cls: 'status-bar-item-icon',
|
||||
attr: {
|
||||
style: 'display: flex; align-items: center;'
|
||||
}
|
||||
});
|
||||
|
||||
// Create loading spinner
|
||||
const spinner = iconEl.createEl('span', {
|
||||
cls: 'openaugi-spinner',
|
||||
attr: {
|
||||
style: `
|
||||
display: inline-block;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
border: 2px solid var(--text-accent);
|
||||
border-radius: 50%;
|
||||
border-top-color: transparent;
|
||||
animation: openaugi-spin 1s linear infinite;
|
||||
`
|
||||
}
|
||||
});
|
||||
|
||||
// Add CSS animation
|
||||
const styleEl = document.head.createEl('style');
|
||||
styleEl.textContent = `
|
||||
@keyframes openaugi-spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
// Create text container
|
||||
const textEl = this.statusBarItem.createEl('span', {
|
||||
text: message,
|
||||
attr: {
|
||||
style: 'font-size: 13px; font-weight: 500;'
|
||||
}
|
||||
});
|
||||
|
||||
// Create dot animation container
|
||||
this.loadingContainer = this.statusBarItem.createEl('span', {
|
||||
attr: { style: 'display: flex; gap: 2px;' }
|
||||
});
|
||||
|
||||
// Create three dots for the animation
|
||||
for (let i = 0; i < 3; i++) {
|
||||
const dot = this.loadingContainer.createEl('span', {
|
||||
text: '.',
|
||||
attr: {
|
||||
style: 'opacity: 0; transition: opacity 0.3s ease; font-weight: bold;'
|
||||
}
|
||||
});
|
||||
this.dotElements.push(dot);
|
||||
}
|
||||
|
||||
// Start dot animation
|
||||
let currentDot = 0;
|
||||
this.animationInterval = window.setInterval(() => {
|
||||
// Reset all dots
|
||||
this.dotElements.forEach(dot => dot.style.opacity = '0');
|
||||
|
||||
// Show dots up to current dot
|
||||
for (let i = 0; i <= currentDot; i++) {
|
||||
this.dotElements[i].style.opacity = '1';
|
||||
}
|
||||
|
||||
// Increment and wrap around
|
||||
currentDot = (currentDot + 1) % this.dotElements.length;
|
||||
}, 500);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide the loading indicator
|
||||
*/
|
||||
hide(): void {
|
||||
if (this.animationInterval) {
|
||||
clearInterval(this.animationInterval);
|
||||
this.animationInterval = null;
|
||||
}
|
||||
|
||||
if (this.statusBarItem) {
|
||||
this.statusBarItem.remove();
|
||||
this.statusBarItem = null;
|
||||
}
|
||||
|
||||
this.dotElements = [];
|
||||
this.loadingContainer = null;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue