Added mobile-specific CSS rules targeting `body.is-mobile` for the
expanded task modal to ensure proper flex layout. The button container
now stays pinned at the bottom without overlapping the scrollable
content area on Obsidian mobile devices.
Make modal content scrollable while keeping action buttons pinned at bottom:
- Set modal-content as flex container with max-height constraint
- Make minimalist-modal-container a flex child that fills available space
- Add overflow-y: auto to modal-split-content for scrollable form fields
- Keep button container fixed with flex-shrink: 0 and visual separator
On wide screens with split-layout, reset overflow to visible since
individual columns handle their own scrolling.
Constrain the expanded modal to max-height: 85vh and use flex layout
so the content area shrinks while the button container stays pinned
at the bottom of the viewport.
- Position details field below title on narrow screens (non-split mode)
- Add thinner (0.5px) section dividers for cleaner appearance
- Remove glow effect from title input on focus
- Add 1200px+ breakpoint with wider modal (1100px) and left column (480px)
Add a two-column layout for task modals on screens 900px+ wide, showing
form fields on the left and the details editor on the right. Includes a
new setting to toggle this behavior.
Also refactors task modal architecture to use template method pattern,
reducing code duplication between TaskCreationModal and TaskEditModal.
Use Obsidian's .is-mobile class to properly detect mobile devices
instead of relying solely on viewport width. The save button's
margin-left: auto now only applies on desktop.
- Add buildMetadataRows method to ProjectMetadataResolver for consistent
metadata row building across NLP autocomplete and ProjectSelectModal
- Convert dynamic imports to static imports in NLPCodeMirrorAutocomplete
for better performance (no longer imports on every keystroke)
- Add debug logging for row config parse errors (dev mode only)
- Add comprehensive tests for buildMetadataRows
- Fix misleading CSS comment about "legacy" styles that are still in use
Enhance the CodeMirror-based NLP autocomplete to display rich project
metadata (title, aliases, path, custom frontmatter) when users type the
project trigger, bringing feature parity with the manual "Add to
Project" button dropdown.
Changes:
- Use CodeMirror 6's addToOptions API for custom rendering
- Display up to 3 configurable metadata rows based on projectAutosuggest.rows settings
- Add ProjectMetadataResolver integration for consistent metadata resolution
- Add CSS styles for metadata display in autocomplete tooltip
This improves UX consistency by ensuring both project selection methods
(NLP-triggered and manual) display the same rich context to help users
identify the correct project.
Based on feedback from kepano to reduce custom styling and use
Obsidian's native styles where possible:
- Replace all `cursor: pointer` with `cursor: var(--cursor)` across
all CSS files (100+ instances). Following Obsidian's convention where
`cursor: pointer` is only for links.
- Remove forced `border: none; box-shadow: none` rules that were
fighting against Obsidian's native button styling.
- Scope custom `.tn-btn` button system to `.mod-settings` only,
allowing Obsidian's native button styles to work elsewhere.
- Add `background: transparent` to mini-calendar buttons to match
Obsidian's native `.text-icon-button` styling.
This makes the plugin more cohesive with Obsidian's UI and reduces
unnecessary style overrides.
Replace custom button styling with Obsidian's native modal button system:
- Use modal-button-container class instead of custom button-container
- Apply mod-cta for primary Save button (native accent styling)
- Apply mod-warning for Archive button (native warning styling)
- Remove custom save-button, cancel-button, button-spacer classes
- Fix button layout: left-align Open note/Archive, right-align Save/Cancel
- Add mod-tasknotes class to modalEl for scoped styling
This provides better consistency with Obsidian's UI and fixes the Archive
button positioning issue where it was appearing in the middle of the modal
instead of aligned with the Open note button.
Added visual differentiation for skipped instances across calendar views,
making it easy to distinguish between completed, skipped, and pending
recurring task instances at a glance.
Bases Calendar View:
- Skipped instances display with gray background (rgba(128,128,128,0.2))
- Lighter background for pattern instances (0.15 opacity)
- Added isSkipped flag to event extendedProps
Task Edit Modal Calendar:
- Skipped instances show with:
- Gray background (rgba(128,128,128,0.3))
- Muted text color
- Strike-through text decoration
- Faint border
- Darker background on hover
- Read-only display of existing skipped instances
- Added recurring-calendar__day--skipped CSS class
Technical Changes:
- Extended CalendarEvent type with isSkipped property
- Updated createNextScheduledEvent() to check and style skipped instances
- Updated createRecurringEvent() to check and style skipped instances
- TaskEditModal now reads and displays skipped_instances from task data
- Added CSS styling in task-modal.css for skipped state
Visual Hierarchy:
- Completed: Bright accent color background, white text
- Skipped: Gray background, muted text with strike-through
- Recurring: Border only, transparent background
- Future: No special styling
This makes it immediately clear which instances were completed vs skipped,
improving the visual feedback for recurring task management.
- Extract PropertySelectorModal to shared location (src/modals/)
- Create shared property list builder utility (src/utils/propertyHelpers.ts)
- Update inline properties setting to use shared modal and helpers
- Replace default properties checkboxes with modal UI for consistency
- User-defined fields now automatically available in both property selectors
- Consistent UX across inline and default property configuration
Changed approach:
- Lines are inline-block with ::after pseudo-element for line breaks
- Empty lines have min-height and no cursor
- max-width animates to 1000px (fixed value instead of 100%)
- Added padding-right to separate text from cursor
- overflow: hidden to crop text during animation
This should make all three lines visible and animate properly.
Fixed two issues:
1. Third line now appears right after first line finishes (not after empty line)
- First line: delay 0ms
- Second line (empty): delay = first line duration
- Third line: delay = first line duration (parallel with empty line)
2. Prevent editor from scrolling down on mount
- Added cm.scrollDOM.scrollTop = 0 after focus
- This keeps the placeholder visible at the top
Fixed issues with animated placeholder:
- Position absolute to overlay on editor properly
- Changed to max-width animation instead of width
- Each line is block display for proper stacking
- Added padding to match editor content area
- Width: fit-content with max-width: 0 for animation
Created a beautiful animated placeholder with typewriter effect that:
- Shows all 3 lines of placeholder text
- Animates each line typing out character by character
- Each line starts 1 second after the previous line
- Includes blinking cursor during typing
- Cursor disappears 1 second after last line completes
- No cursor bug because it's a widget, not actual editor lines!
Implementation:
1. PlaceholderWidget creates separate divs for each line
2. Each line has CSS custom properties for animation timing:
- --typing-duration: Based on line length (50ms per character)
- --typing-delay: Staggered by line (1000ms between lines)
- --char-count: Number of characters for step animation
3. CSS animations:
- typing: Expands width from 0 to 100% using steps()
- blink-caret: Border blinks during typing
- remove-caret: Hides cursor after animation completes
Effect:
Line 1: "Buy groceries..." types out (0s delay)
Line 2: Empty line (1s delay)
Line 3: "Add details here..." types out (2s delay)
Cursor disappears at ~5s total
Much more engaging than static placeholder! ✨
Root cause: CodeMirror's placeholder() extension creates multiple line
elements for multi-line placeholder text, causing multiple cursors to appear.
Solution: Replaced placeholder() extension with custom PlaceholderWidget that:
- Only shows the first line of placeholder text
- Renders as a single widget decoration
- Avoids creating multiple line elements
- Prevents multi-cursor bug entirely
Implementation:
- Created PlaceholderWidget class extending WidgetType
- Uses EditorView.decorations.compute() to show widget only when doc is empty
- Extracts first line from placeholder text: placeholder.split('\n')[0]
- Removed CSS workarounds (no longer needed)
Now placeholder shows "Buy groceries tomorrow at 3pm @home #errands"
without the "Add details here..." line, and cursor appears normally.
When multi-line placeholder text is shown, CodeMirror creates multiple
cursor instances (one per line). This fix hides all but the first cursor
when the placeholder is visible.
CSS: Hide all .cm-cursor elements except :first-of-type when .cm-placeholder exists
Reverted line-height back to 1.5 as requested
Reduced line-height from 1.5 to 1.3 in NLP markdown editor to make
the multi-line placeholder text render more compactly. This prevents
the placeholder from appearing overly spread out across multiple lines.
Implements issue #752 - customizable trigger strings for all property types.
Major changes:
- Add PropertyTriggerConfig and NLPTriggersConfig types
- Add TriggerConfigService for managing trigger configurations
- Update NaturalLanguageParser to use configurable triggers (not hard-coded)
- Rewrite NLPCodeMirrorAutocomplete with dynamic trigger discovery
- Add comprehensive settings UI for configuring triggers
- Add user field extraction and preview support
- Fix whitespace preservation in trigger strings
- Add migration from old statusSuggestionTrigger setting
Features:
- Multi-character triggers (e.g., "context:", "project:")
- User-defined property triggers with autocomplete
- Smart tag handling (native vs custom suggester)
- Extraction and population of user fields on task creation
- Extensive debug logging for troubleshooting
Files modified:
- src/types/settings.ts - New trigger types
- src/settings/defaults.ts - Default trigger configuration
- src/services/TriggerConfigService.ts - NEW service
- src/services/NaturalLanguageParser.ts - Dynamic triggers
- src/editor/NLPCodeMirrorAutocomplete.ts - Complete rewrite
- src/modals/TaskCreationModal.ts - User field population
- src/settings/tabs/featuresTab.ts - Settings UI
- src/main.ts - Settings migration
Build: Successful, 2.7MB, zero TypeScript errors
- Move padding from cm-content to cm-scroller
- Reset cm-content padding to 0 with !important
- Reset cm-line padding to prevent double padding
- Now text has proper spacing from border edges
Padding is now applied at the scroller level to ensure it works correctly.
- Background: var(--background-secondary) by default
- Focus: border-color changes to --interactive-accent
- Focus: background changes to --background-primary
- Focus: add accent glow shadow (2px rgba)
- Padding: var(--size-4-3) var(--size-4-2) to match old input
- Line height: 1.5 to match old textarea
- Placeholder: --text-muted color
- Smooth transition on all changes (0.2s ease)
Now the markdown editor looks and feels just like the old textarea!
Prefix all CodeMirror autocomplete styles with .tasknotes-plugin
to prevent affecting other plugins or Obsidian's native editors.
This ensures our styling is isolated to TaskNotes UI components.