This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Notice: 构建的时候请优先使用 npm run build:local 。
Yearly Glance is an Obsidian plugin that provides a visual yearly calendar view for managing holidays, birthdays, and custom events. It supports both Gregorian and Chinese lunar calendars, with multi-language support (English, Simplified Chinese, Traditional Chinese).
Tech Stack: TypeScript 4.7.4, React 19, esbuild 0.27.1, PostCSS with nesting support
# Development (watch mode)
npm run dev
# Production build
npm run build
# Build + copy to local vault (requires .env with VAULT_PATH)
npm run build:local
# Type checking
npx tsc --noEmit
# Linting
npm run lint # Check
npm run lint:fix # Auto-fix
# Testing
npm test # Run Jest tests
npm run test:watch # Jest watch mode
# Versioning & Release
npm run version # Bump version and update manifests
npm run release:pre # Build + version + changelog- Entry Point:
src/main.ts - Output:
main.js(bundle),styles.css(from PostCSS) - External Dependencies: obsidian, electron, CodeMirror modules (not bundled)
- CSS Processing: PostCSS with nesting plugin (allows SCSS-like syntax)
- TypeScript: ES2017 target, ESNext modules, React JSX transform
Plugin Structure (src/main.ts)
The plugin follows the standard Obsidian plugin pattern with three view types:
- YearlyGlanceView (
VIEW_TYPE_YEARLY_GLANCE): Main calendar view - GlanceManagerView (
VIEW_TYPE_GLANCE_MANAGER): Management interface (Events, Import/Export, Settings) - YearlyGlanceBasesView (
VIEW_TYPE_YEARLY_GLANCE_BASES): BasesView integration for rendering events from note frontmatter
Three event types with shared BaseEvent interface:
- Holiday: Fixed/recurring holidays with
foundDatefor anniversaries - Birthday: Annual birthdays with calculated age, zodiac, animal
- CustomEvent: User-defined events with repeat support
Event Sources (EventSource enum):
CONFIG: Stored in plugin settingsBASES: From note frontmatter (via Obsidian Bases)CODEBLOCK: Future support for markdown code blocks
Event ID Format: {source}-{filePath}-{isoDate} (e.g., bases-Events/event.md-2026-01-10)
Pub/Sub Event Bus (src/hooks/useYearlyGlanceConfig.ts):
YearlyGlanceBus.subscribe(callback) // Subscribe to changes
YearlyGlanceBus.publish() // Notify all subscribersUsed by React components via useYearlyGlanceConfig hook to sync plugin settings across views.
-
Settings stored in
YearlyGlanceConfigwith two parts:config: Display preferences (year, layout, colors, visibility)data: Event collections (holidays, birthdays, customEvents)
-
On plugin load (
loadSettings()):- Load and validate saved data
- Run migrations via
MigrateData.migrateV2() - Update all events'
dateArrfield viaEventCalculator - Add sample event on first install
-
On settings save (
saveSettings()):- Persist to Obsidian data store
- Publish to
YearlyGlanceBusto notify components
- EventCalculator (src/utils/eventCalculator.ts): Core date calculation logic (Gregorian/Lunar conversion, recurring events, birthday age/zodiac)
- DateParseService (src/services/dateParseService.ts): Parses user input dates
- iCalendarService (src/services/iCalendarService.ts): ICS export
- JsonService (src/services/jsonService.ts): JSON import/export
- MarkdownService (src/services/markdownService.ts): Frontmatter parsing/export
Custom i18n system (src/i18n/i18n.ts):
- Singleton
I18nclass with flattened translation keys - Supported locales:
en,zh,zh-TW - Auto-detects Obsidian language
- Usage:
t(key, params)for template string interpolation
YearlyGlanceBasesView integrates with Obsidian's Bases database feature:
- Reads events from note frontmatter
- Configurable property mapping (title, date)
- Option to inherit plugin data
- Bidirectional sync: updates frontmatter when events are modified via
syncBasesEventToFrontmatter()
React 19 with createRoot API. Component hierarchy:
YearlyCalendar
├── YearlyCalendarView
│ ├── Control Bar (year nav, view presets, toggles)
│ ├── Month Grid (12 months)
│ └── EventTooltip (modal for details)
Feature Components:
├── EventForm (add/edit modal)
├── EventManager (list view with sorting/filtering)
├── DataPortManager (import/export)
└── SettingsTab (configuration)
Base reusable components in src/components/base/: Form components (Input, Select, Toggle, DateInput, Autocomplete), Action components (Button, ConfirmDialog), Display components (Tooltip, CalloutBlock, ColorSelector).
When adding new config fields, update:
DEFAULT_CONFIG- Default valuesMigrateData.migrateV2()- Migration logic
- Extend
BaseEventinterface - Add to
EventTypeandEVENT_TYPE_LIST - Update
EVENT_TYPE_DEFAULT - Add to
Eventsinterface - Update
EventCalculatorfor date calculations
Add keys to all locale files in src/i18n/locales/. Keys are flattened at runtime (dot-notation access).
ESLint with TypeScript rules. The following can be ignored:
no-explicit-anyno-unused-vars(withargs: noneoption)no-non-null-assertion
Use npm run lint:fix for auto-fixing.
Uses Conventional Commits. Use npx cz for interactive commit formatting.