new command for finding current day

This commit is contained in:
Ben Floyd 2025-08-18 18:15:01 -06:00
parent 9ba5e5be75
commit d745da2d80
3 changed files with 195 additions and 1 deletions

View file

@ -38,4 +38,21 @@ This view displays each stream as a card showing:
- Total number of files
- Files created this year and month
- Last modified date
- Quick action buttons to open today's note or view the full stream
- Quick action buttons to open today's note or view the full stream
## Commands
The plugin provides several commands accessible via the Command Palette:
- **Open Current Stream Today**: Automatically detects which stream the current view belongs to and opens that stream's today note. This works whether you're in a file that belongs to a stream, a stream view, or a create file view. This is useful when you want to quickly jump to today's note for the current stream context.
- **Open All Streams View**: Opens the dashboard view showing all streams.
- **Toggle calendar component**: Shows/hides the calendar component.
- **Toggle calendar compact mode**: Switches between compact and full calendar display.
Individual stream commands are also available if enabled in stream settings:
- **Stream Name, today**: Opens today's note for a specific stream.
- **Open full view: Stream Name**: Opens the full stream view for a specific stream.
### Keyboard Shortcuts
You can assign custom keyboard shortcuts to any of these commands through Obsidian's Settings → Hotkeys. Some recommended shortcuts:
- **Open Current Stream Today**: `Ctrl+Shift+T` (or `Cmd+Shift+T` on Mac)
- **Open All Streams View**: `Ctrl+Shift+A` (or `Cmd+Shift+A` on Mac)

11
main.ts
View file

@ -4,6 +4,7 @@ import { Stream, StreamsSettings, LucideIcon } from './types';
import { CalendarComponent } from './src/components/CalendarComponent';
import { Logger, LogLevel } from './src/utils/Logger';
import { OpenTodayStreamCommand } from './src/commands/OpenTodayStreamCommand';
import { OpenCurrentStreamTodayCommand } from './src/commands/OpenCurrentStreamTodayCommand';
import { StreamSelectionModal } from './src/modals/StreamSelectionModal';
import { CREATE_FILE_VIEW_TYPE, CreateFileView } from './src/views/CreateFileView';
import { STREAM_VIEW_TYPE, StreamView } from './src/views/StreamView';
@ -775,6 +776,16 @@ export default class StreamsPlugin extends Plugin {
command.execute();
}
});
// Add command to open current stream's today note
this.addCommand({
id: 'open-current-stream-today',
name: 'Open Current Stream Today',
callback: () => {
const command = new OpenCurrentStreamTodayCommand(this.app, this.settings.streams, this.settings.reuseCurrentTab);
command.execute();
}
});
}
private registerCalendarCommands(): void {

View file

@ -0,0 +1,166 @@
import { App, MarkdownView, WorkspaceLeaf, Notice, ItemView } from 'obsidian';
import { Stream } from '../../types';
import { openStreamDate } from '../utils/streamUtils';
import { Logger } from '../utils/Logger';
import { Command } from './Command';
import { STREAM_VIEW_TYPE } from '../views/StreamView';
import { CREATE_FILE_VIEW_TYPE } from '../views/CreateFileView';
import { ALL_STREAMS_VIEW_TYPE } from '../views/AllStreamsView';
const log = new Logger();
export class OpenCurrentStreamTodayCommand implements Command {
constructor(
private app: App,
private streams: Stream[],
private reuseCurrentTab: boolean = false
) {}
async execute(): Promise<void> {
log.debug('Executing OpenCurrentStreamTodayCommand');
// Check if there are any streams configured
if (this.streams.length === 0) {
log.debug('No streams configured');
new Notice('No streams configured. Please add streams in the plugin settings first.');
return;
}
// Try to find the current stream based on active view
const currentStream = this.findCurrentStream();
if (!currentStream) {
log.debug('No current stream found, cannot open today note');
new Notice('No stream context found. Please open a file that belongs to a stream, or use a stream-specific view.');
return;
}
log.debug(`Opening today's note for current stream: ${currentStream.name}`);
await openStreamDate(this.app, currentStream, new Date(), this.reuseCurrentTab);
}
private findCurrentStream(): Stream | null {
const activeLeaf = this.app.workspace.activeLeaf;
if (!activeLeaf) {
log.debug('No active leaf found');
return null;
}
const view = activeLeaf.view;
if (!view) {
log.debug('No view found in active leaf');
return null;
}
// Handle markdown views (most common case)
if (view instanceof MarkdownView) {
const file = view.file;
if (file) {
return this.findStreamByFilePath(file.path);
} else {
log.debug('MarkdownView has no file');
return null;
}
}
// Handle other view types
const viewType = view.getViewType();
log.debug(`Active view type: ${viewType}`);
// Handle StreamView - extract stream from view state
if (viewType === STREAM_VIEW_TYPE) {
const streamView = view as any; // Cast to access private properties
if (streamView.stream && this.isValidStream(streamView.stream)) {
log.debug(`Found stream from StreamView: ${streamView.stream.name}`);
return streamView.stream;
}
}
// Handle CreateFileView - extract stream from view state
if (viewType === CREATE_FILE_VIEW_TYPE) {
const createView = view as any; // Cast to access private properties
if (createView.stream && this.isValidStream(createView.stream)) {
log.debug(`Found stream from CreateFileView: ${createView.stream.name}`);
return createView.stream;
}
}
// Handle AllStreamsView - this view doesn't have a specific stream
if (viewType === ALL_STREAMS_VIEW_TYPE) {
log.debug('User is in All Streams view - no specific stream context');
new Notice('Please select a specific stream or open a file that belongs to a stream.');
return null;
}
// For other view types, try to extract stream from view state if possible
if (view instanceof ItemView) {
try {
const state = view.getState();
if (state && state.stream && this.isValidStream(state.stream)) {
log.debug(`Found stream from view state: ${state.stream.name}`);
return state.stream;
}
} catch (error) {
log.debug('Could not extract stream from view state:', error);
}
}
log.debug('No stream found in current view');
return null;
}
private isValidStream(stream: any): stream is Stream {
return stream &&
typeof stream === 'object' &&
typeof stream.id === 'string' &&
typeof stream.name === 'string' &&
typeof stream.folder === 'string' &&
typeof stream.icon === 'string';
}
private findStreamByFilePath(filePath: string): Stream | null {
log.debug(`Looking for stream matching file: ${filePath}`);
// Find which stream this file belongs to
const stream = this.streams.find(s => {
// Skip streams with empty folders
if (!s.folder || s.folder.trim() === '') {
return false;
}
// Normalize paths for comparison
const normalizedFilePath = filePath.split(/[/\\]/).filter(Boolean);
const normalizedStreamPath = s.folder.split(/[/\\]/).filter(Boolean);
// If stream path is empty, skip this stream
if (normalizedStreamPath.length === 0) {
return false;
}
// Check if the file path starts with the stream path
const isInStreamFolder = normalizedStreamPath.every((part, index) => {
// Check bounds
if (index >= normalizedFilePath.length) {
return false;
}
return normalizedStreamPath[index] === normalizedFilePath[index];
});
log.debug(`Checking stream "${s.name}" (${s.folder}):`, {
isInStreamFolder,
normalizedFilePath,
normalizedStreamPath
});
return isInStreamFolder;
});
if (stream) {
log.debug(`File belongs to stream: ${stream.name} (${stream.folder})`);
return stream;
} else {
log.debug('File does not belong to any stream');
return null;
}
}
}