Compare commits

..

No commits in common. "master" and "0.0.3" have entirely different histories.

12 changed files with 132 additions and 734 deletions

View file

@ -1,6 +1,6 @@
# OZ Calendar Plugin
If you like the see your notes on a Calendar and easily find them using a certain date, you are at the right place. This plugin is created to help users easily view notes on Calendar using any YAML key or File Name with a custom date value. You define the YAML key and Date Format to be used. Or you can simply use the file name with your custom date format. Follow the **Configure** steps depending on your choice and you are ready to go.
If you like the see your notes on a Calendar and easily find them using a certain date, you are at the right place. This plugin is created to help users easily view notes on Calendar using any YAML key with a custom date value. You define the YAML key and Date Format to be used. Follow the **Configure** steps and you are ready to go.
## Sample View
@ -8,10 +8,6 @@ If you like the see your notes on a Calendar and easily find them using a certai
## Configure
> IMPORTANT: Please make sure that you check the date formatting of the library, which is used by this plugin following [Day.js Date Format Link](https://day.js.org/docs/en/display/format).
### 01 YAML Option as Date Source
1. Go to the plugin settings
2. Define the **YAML** key you want to use as a date field. The default key is **created**
3. Define the **Date Format** you are using within **YAML**. The default date format is **YYYY-MM-DD hh:mm:ss**
@ -27,17 +23,6 @@ created: 2023-03-10 09:48:22
You can use any YAML key instead of "created" and any date format value for the key.
### 02 File Name Option as Date Source
The default date source is the YAML Key ("created") as mentioned above. If you want to use the file name as date source that feeds the calendar:
1. Go to the plugin settings
2. Change Date Source from **YAML** to **File Name** since the plugin has **YAML** key as a default date source
3. Make sure that you adjust the default date format (**Important**: The default date format has special characters that is not supported for file name like colon that needs to be adjusted for File Name option)
4. After these changes, use **Reload Plugin** option to activate the changes in the vault.
> Both YAML and File Name options can include additional characters in the file name. As long as the custom date format defined in the plugin settings is at the beginning of the YAML key or File Name, the plugin will be smart enough to parse only the beginning of the key/filename. For instance, if you have a file name '**2023-03-10 This is the file**' and your date format defined in the plugin settings is **YYYY-MM-DD**, it will be parsed just fine in the calendar.
## Create File Option
You can use the **Plus(+)** icon within the calendar view to add a new note with the default YAML key and date format.
@ -49,16 +34,6 @@ You can define this in the plugin settings:
- You can right-click any date in the calendar view to create a note for a certain date
- The plus icon is defaulted to create a note for today
## Plugin Commands
### Day Navigation
You can use directly **Go to Previous Day**, **Go to Next Day** and **Go to Today** commands to navigate between dates. You can also assign hotkey to these commands to change the active date easily from your keyboard.
### New Note Creation
You can use the **Create a New Note** command to trigger the create a new note action customized for the plugin. Same as day navigation, you can assign hotkey to this command for easy keyboard navigation.
## Style Settings Plugin Support
You can customize some of the calendar style settings using the **Style Settings Plugin**.

View file

@ -1,7 +1,7 @@
{
"id": "oz-calendar",
"name": "OZ Calendar",
"version": "0.3.4",
"version": "0.0.2",
"minAppVersion": "0.15.0",
"description": "View your notes in Calendar using any YAML key with date",
"author": "Ozan Tellioglu",

View file

@ -1,6 +1,6 @@
{
"name": "oz-calendar",
"version": "0.3.4",
"version": "0.0.2",
"description": "View your notes in Calendar using any YAML key with date",
"main": "main.js",
"scripts": {
@ -14,9 +14,9 @@
"devDependencies": {
"@types/common-tags": "^1.8.1",
"@types/node": "^16.11.6",
"@types/react": "18.2.38",
"@types/react": "17.0.2",
"@types/react-calendar": "^3.9.0",
"@types/react-dom": "18.2.17",
"@types/react-dom": "17.0.2",
"@typescript-eslint/eslint-plugin": "5.29.0",
"@typescript-eslint/parser": "5.29.0",
"builtin-modules": "3.3.0",
@ -30,9 +30,10 @@
"@popperjs/core": "^2.11.6",
"common-tags": "^1.8.2",
"dayjs": "1.11.7",
"react": "18.2.0",
"preact": "10",
"react": "npm:@preact/compat@17.0.2",
"react-calendar": "4.0.0",
"react-dom": "18.2.0",
"react-dom": "npm:@preact/compat@17.0.2",
"react-icons": "4.8.0"
}
}

View file

@ -5,8 +5,6 @@ import OZCalendarPlugin from '../main';
import NoteListComponent from './noteList';
import dayjs from 'dayjs';
import useForceUpdate from 'hooks/forceUpdate';
import { DayChangeCommandAction } from 'types';
import { CreateNoteModal } from 'modal';
export default function MyCalendar(params: { plugin: OZCalendarPlugin }) {
const { plugin } = params;
@ -18,57 +16,11 @@ export default function MyCalendar(params: { plugin: OZCalendarPlugin }) {
useEffect(() => {
window.addEventListener(plugin.EVENT_TYPES.forceUpdate, forceUpdate);
window.addEventListener(plugin.EVENT_TYPES.changeDate, changeDate);
window.addEventListener(plugin.EVENT_TYPES.createNote, createNote);
return () => {
window.removeEventListener(plugin.EVENT_TYPES.forceUpdate, forceUpdate);
window.removeEventListener(plugin.EVENT_TYPES.changeDate, changeDate);
window.removeEventListener(plugin.EVENT_TYPES.createNote, createNote);
};
}, []);
const createNote = () => {
let currentSelectedDay: Date = selectedDay;
let dateNow: Date = new Date();
setSelectedDay((selectedDay) => {
currentSelectedDay = selectedDay;
return selectedDay;
});
// Add now time details to the existing date if current date
if (plugin.settings.newNoteDate === 'active-date') {
currentSelectedDay.setHours(dateNow.getHours());
currentSelectedDay.setMinutes(dateNow.getMinutes());
currentSelectedDay.setMilliseconds(dateNow.getMilliseconds());
}
let newFileModal = new CreateNoteModal(
plugin,
plugin.settings.newNoteDate === 'current-date' ? dateNow : currentSelectedDay
);
newFileModal.open();
};
const changeDate = (e: CustomEvent) => {
let action = e.detail.action as DayChangeCommandAction;
let currentSelectedDay = selectedDay;
// Event listener is not capable of getting the updates after event listener is added
// This is created to capture current state value during the custom event dispatch
setSelectedDay((selectedDay) => {
currentSelectedDay = selectedDay;
return selectedDay;
});
let newDate = dayjs(currentSelectedDay);
if (action === 'next-day') {
newDate = dayjs(currentSelectedDay).add(1, 'day');
} else if (action === 'previous-day') {
newDate = dayjs(currentSelectedDay).add(-1, 'day');
} else if (action === 'today') {
newDate = dayjs();
}
setSelectedDay(newDate.toDate());
};
const customTileContent = ({ date, view }: CalendarTileProperties) => {
if (view === 'month') {
const dateString = dayjs(date).format('YYYY-MM-DD');
@ -77,7 +29,7 @@ export default function MyCalendar(params: { plugin: OZCalendarPlugin }) {
return (
<div className="dots-wrapper">
{[...Array(Math.min(dotsCount, 2))].map((_, index) => (
<RxDotFilled key={index} viewBox="0 0 15 15" />
<RxDotFilled viewBox="0 0 15 15" />
))}
{dotsCount > 2 && <span>+{dotsCount - 2}</span>}
</div>
@ -86,31 +38,15 @@ export default function MyCalendar(params: { plugin: OZCalendarPlugin }) {
return null;
};
const customTileClass = ({ activeStartDate, date, view }: CalendarTileProperties) => {
// Assign a custom class in case the day is the current day
let today = new Date();
return date.getFullYear() === today.getFullYear() &&
date.getMonth() === today.getMonth() &&
date.getDate() === today.getDate()
? 'oz-calendar-plugin-today'
: '';
};
const fixedCalendarClass = plugin.settings.fixedCalendar ? 'fixed' : '';
return (
<div className={'oz-calendar-plugin-view ' + fixedCalendarClass}>
<div className={'oz-calendar-plugin-view' + (plugin.settings.fixedCalendar ? ' fixed' : '')}>
<Calendar
onChange={setSelectedDay}
value={selectedDay}
maxDetail="month"
minDetail="month"
showWeekNumbers={plugin.settings.showWeekNumbers}
view="month"
tileContent={customTileContent}
tileClassName={customTileClass}
calendarType={plugin.settings.calendarType}
showFixedNumberOfWeeks={plugin.settings.fixedCalendar}
activeStartDate={activeStartDate}
onActiveStartDateChange={(props) => {
if (props.action === 'next') {
@ -133,7 +69,6 @@ export default function MyCalendar(params: { plugin: OZCalendarPlugin }) {
setActiveStartDate={setActiveStartDate}
plugin={plugin}
forceValue={forceValue}
createNote={createNote}
/>
</>
</div>

View file

@ -7,20 +7,18 @@ import dayjs from 'dayjs';
import OZCalendarPlugin from 'main';
import { isMouseEvent, openFile } from '../util/utils';
import { Menu, TFile } from 'obsidian';
import { VIEW_TYPE } from 'view';
import { OZNote } from 'types';
import { CreateNoteModal } from 'modal';
interface NoteListComponentParams {
selectedDay: Date;
setSelectedDay: (selectedDay: Date) => void;
setActiveStartDate: (newActiveStartDate: Date) => void;
createNote: () => void;
plugin: OZCalendarPlugin;
forceValue: number;
}
export default function NoteListComponent(params: NoteListComponentParams) {
const { setSelectedDay, selectedDay, plugin, setActiveStartDate, forceValue, createNote } = params;
const { setSelectedDay, selectedDay, plugin, setActiveStartDate, forceValue } = params;
const setNewSelectedDay = (nrChange: number) => {
let newDate = dayjs(selectedDay).add(nrChange, 'day');
@ -37,48 +35,29 @@ export default function NoteListComponent(params: NoteListComponentParams) {
}
};
const openFilePath = (e: React.MouseEvent<HTMLDivElement, MouseEvent>, filePath: string) => {
const openFilePath = (filePath: string) => {
let abstractFile = plugin.app.vault.getAbstractFileByPath(filePath);
let openFileBehaviour = plugin.settings.openFileBehaviour;
if (abstractFile && abstractFile instanceof TFile) {
// Define the Default Open Behaviour by looking at the plugin settings
let openInNewLeaf: boolean = openFileBehaviour === 'new-tab';
let openInNewTabGroup: boolean = openFileBehaviour === 'new-tab-group';
if (openFileBehaviour === 'obsidian-default') {
openInNewLeaf = (e.ctrlKey || e.metaKey) && !(e.shiftKey || e.altKey);
openInNewTabGroup = (e.ctrlKey || e.metaKey) && (e.shiftKey || e.altKey);
}
// Open the file by using the open file behaviours above
if (abstractFile) {
openFile({
file: abstractFile,
file: abstractFile as TFile,
plugin: plugin,
newLeaf: openInNewLeaf,
leafBySplit: openInNewTabGroup,
newLeaf: openFileBehaviour === 'new-tab',
leafBySplit: openFileBehaviour === 'new-tab-group',
});
}
};
const selectedDayNotes: OZNote[] = useMemo(() => {
const selectedDayNotes = useMemo(() => {
const selectedDayIso = dayjs(selectedDay).format('YYYY-MM-DD');
let sortedList: OZNote[] = [];
if (selectedDayIso in plugin.OZCALENDARDAYS_STATE) {
sortedList = plugin.OZCALENDARDAYS_STATE[selectedDayIso].filter(
(ozItem) => ozItem.type === 'note'
) as OZNote[];
}
sortedList = sortedList.sort((a, b) => {
if (plugin.settings.sortingOption === 'name-rev')
[a.displayName, b.displayName] = [b.displayName, a.displayName];
return a.displayName.localeCompare(b.displayName, 'en', { numeric: true });
});
return sortedList;
return selectedDayIso in plugin.OZCALENDARDAYS_STATE ? plugin.OZCALENDARDAYS_STATE[selectedDayIso] : [];
}, [selectedDay, forceValue]);
const triggerFileContextMenu = (e: React.MouseEvent | React.TouchEvent, filePath: string) => {
let abstractFile = plugin.app.vault.getAbstractFileByPath(filePath);
if (abstractFile) {
const fileMenu = new Menu();
plugin.app.workspace.trigger('file-menu', fileMenu, abstractFile, VIEW_TYPE);
plugin.app.workspace.trigger('file-menu', fileMenu, abstractFile, 'file-explorer');
if (isMouseEvent(e)) {
fileMenu.showAtPosition({ x: e.pageX, y: e.pageY });
} else {
@ -92,7 +71,14 @@ export default function NoteListComponent(params: NoteListComponentParams) {
<>
<div className="oz-calendar-notelist-header-container">
<div className="oz-calendar-nav-action-plus">
<RiAddCircleLine size={20} aria-label="Create note for today" onClick={createNote} />
<RiAddCircleLine
size={20}
aria-label="Create note for today"
onClick={() => {
let newFileModal = new CreateNoteModal(plugin, new Date());
newFileModal.open();
}}
/>
</div>
<div className="oz-calendar-nav-action-left">
<BsArrowLeft size={22} aria-label="Go to previous day" onClick={() => setNewSelectedDay(-1)} />
@ -117,32 +103,22 @@ export default function NoteListComponent(params: NoteListComponentParams) {
/>
</div>
</div>
<div
className={
'oz-calendar-notelist-container ' +
(plugin.settings.fileNameOverflowBehaviour == 'scroll' ? 'oz-calendar-overflow-scroll' : '')
}>
<div className="oz-calendar-notelist-container">
{selectedDayNotes.length === 0 && (
<div className="oz-calendar-note-no-note">
<RiPhoneFindLine className="oz-calendar-no-note-icon" />
No note found
</div>
)}
{selectedDayNotes.map((ozNote) => {
{selectedDayNotes.map((notePath) => {
return (
<div
className={
'oz-calendar-note-line' +
(plugin.settings.fileNameOverflowBehaviour == 'hide'
? ' oz-calendar-overflow-hide'
: '')
}
id={ozNote.path}
key={ozNote.path}
onClick={(e) => openFilePath(e, ozNote.path)}
onContextMenu={(e) => triggerFileContextMenu(e, ozNote.path)}>
className="oz-calendar-note-line"
id={notePath}
onClick={() => openFilePath(notePath)}
onContextMenu={(e) => triggerFileContextMenu(e, notePath)}>
<HiOutlineDocumentText className="oz-calendar-note-line-icon" />
<span>{ozNote.displayName}</span>
<span>{extractFileName(notePath)}</span>
</div>
);
})}

View file

@ -2,20 +2,16 @@ import { CachedMetadata, Menu, Plugin, TAbstractFile, TFile, addIcon } from 'obs
import { OZCalendarView, VIEW_TYPE } from 'view';
import dayjs from 'dayjs';
import customParseFormat from 'dayjs/plugin/customParseFormat';
import { DayChangeCommandAction, OZCalendarDaysMap, fileToOZItem } from 'types';
import { OZCalendarDaysMap } from 'types';
import { OZCAL_ICON } from './util/icons';
import { OZCalendarPluginSettings, DEFAULT_SETTINGS, OZCalendarPluginSettingsTab } from './settings/settings';
import { CreateNoteModal } from 'modal';
export default class OZCalendarPlugin extends Plugin {
settings: OZCalendarPluginSettings;
dayjs = dayjs;
OZCALENDARDAYS_STATE: OZCalendarDaysMap = {};
initialScanCompleted: boolean = false;
EVENT_TYPES = {
forceUpdate: 'ozCalendarForceUpdate',
changeDate: 'ozCalendarChangeDate',
createNote: 'ozCalendarCreateNote',
};
dayMonthSelectorQuery = '.oz-calendar-plugin-view .react-calendar__tile.react-calendar__month-view__days__day';
@ -33,91 +29,19 @@ export default class OZCalendarPlugin extends Plugin {
return new OZCalendarView(leaf, this);
});
this.app.metadataCache.on('resolved', () => {
// Run only during initial vault load, changes are handled separately
if (!this.initialScanCompleted) {
this.OZCALENDARDAYS_STATE = this.getNotesWithDates();
this.initialScanCompleted = true;
this.calendarForceUpdate();
}
});
this.app.workspace.onLayoutReady(() => {
this.OZCALENDARDAYS_STATE = this.getNotesWithDates();
if (this.settings.openViewOnStart) {
this.openOZCalendarLeaf({ showAfterAttach: true });
}
this.OZCALENDARDAYS_STATE = this.getNotesWithDates();
});
this.registerEvent(this.app.metadataCache.on('changed', this.handleCacheChange));
this.registerEvent(this.app.vault.on('rename', this.handleRename));
this.registerEvent(this.app.vault.on('delete', this.handleDelete));
this.registerEvent(this.app.vault.on('create', this.handleCreate));
this.app.metadataCache.on('changed', this.handleCacheChange);
this.app.vault.on('rename', this.handleRename);
this.app.vault.on('delete', this.handleDelete);
// Add Event Handler for Custom Note Creation
document.on('contextmenu', this.dayMonthSelectorQuery, this.handleMonthDayContextMenu);
this.addCommand({
id: 'oz-calendar-next-day',
name: 'Go to Next Day',
callback: () => {
window.dispatchEvent(
new CustomEvent(this.EVENT_TYPES.changeDate, {
detail: {
action: 'next-day' as DayChangeCommandAction,
},
})
);
},
});
this.addCommand({
id: 'oz-calendar-previous-day',
name: 'Go to Previous Day',
callback: () => {
window.dispatchEvent(
new CustomEvent(this.EVENT_TYPES.changeDate, {
detail: {
action: 'previous-day' as DayChangeCommandAction,
},
})
);
},
});
this.addCommand({
id: 'oz-calendar-today',
name: 'Go to Today',
callback: () => {
window.dispatchEvent(
new CustomEvent(this.EVENT_TYPES.changeDate, {
detail: {
action: 'today' as DayChangeCommandAction,
},
})
);
},
});
this.addCommand({
id: 'oz-calendar-new-note',
name: 'Create a New Note',
callback: () => {
window.dispatchEvent(
new CustomEvent(this.EVENT_TYPES.createNote, {
detail: {},
})
);
},
});
this.addCommand({
id: 'oz-calendar-open-leaf',
name: 'Open OZ Calendar',
callback: () => {
this.openOZCalendarLeaf({ showAfterAttach: true });
},
});
}
onunload() {
@ -135,35 +59,23 @@ export default class OZCalendarPlugin extends Plugin {
/* ------------ HANDLE VAULT CHANGES - HELPERS ------------ */
/**
* Adds the provided filePath to the corresponding date within plugin state
* @param date
* @param filePath
*/
addFilePathToState = (date: string, file: TFile) => {
addFilePathToState = (date: string, filePath: string) => {
let newStateMap = this.OZCALENDARDAYS_STATE;
// if exists, add the new file path
if (date in newStateMap) {
newStateMap[date] = [...newStateMap[date], fileToOZItem({ note: file })];
newStateMap[date] = [...newStateMap[date], filePath];
} else {
newStateMap[date] = [fileToOZItem({ note: file })];
newStateMap[date] = [filePath];
}
this.OZCALENDARDAYS_STATE = newStateMap;
};
/**
* Scans the plugin state and removes the file path if found
* @param filePath
* @returns true if the file path is found and deleted
*/
removeFilePathFromState = (filePath: string): boolean => {
let changeFlag = false;
let newStateMap = this.OZCALENDARDAYS_STATE;
for (let k of Object.keys(newStateMap)) {
if (newStateMap[k].some((ozItem) => ozItem.type === 'note' && ozItem.path === filePath)) {
newStateMap[k] = newStateMap[k].filter((ozItem) => {
return !(ozItem.type === 'note' && ozItem.path === filePath);
});
if (newStateMap[k].contains(filePath)) {
newStateMap[k] = newStateMap[k].filter((p) => p !== filePath);
changeFlag = true;
}
}
@ -171,11 +83,6 @@ export default class OZCalendarPlugin extends Plugin {
return changeFlag;
};
/**
* Scans the file provided for users date key and adds to the plugin state
* @param file
* @returns boolean (if any change happened, true)
*/
scanTFileDate = (file: TFile): boolean => {
let cache = this.app.metadataCache.getCache(file.path);
let changeFlag = false;
@ -183,9 +90,9 @@ export default class OZCalendarPlugin extends Plugin {
let fm = cache.frontmatter;
for (let k of Object.keys(cache.frontmatter)) {
if (k === this.settings.yamlKey) {
let fmValue = String(fm[k]);
let fmValue = fm[k];
let parsedDayISOString = dayjs(fmValue, this.settings.dateFormat).format('YYYY-MM-DD');
this.addFilePathToState(parsedDayISOString, file);
this.addFilePathToState(parsedDayISOString, file.path);
changeFlag = true;
}
}
@ -193,9 +100,6 @@ export default class OZCalendarPlugin extends Plugin {
return changeFlag;
};
/**
* Use this function to force update the calendar and file list view
*/
calendarForceUpdate = () => {
window.dispatchEvent(
new CustomEvent(this.EVENT_TYPES.forceUpdate, {
@ -207,69 +111,34 @@ export default class OZCalendarPlugin extends Plugin {
/* ------------ HANDLE VAULT CHANGES - LISTENER FUNCTIONS ------------ */
handleCacheChange = (file: TFile, data: string, cache: CachedMetadata) => {
if (this.settings.dateSource === 'yaml') {
this.removeFilePathFromState(file.path);
if (cache && cache.frontmatter) {
let fm = cache.frontmatter;
for (let k of Object.keys(cache.frontmatter)) {
if (k === this.settings.yamlKey) {
let fmValue = String(fm[k]);
let parsedDayISOString = dayjs(fmValue, this.settings.dateFormat).format('YYYY-MM-DD');
// If date doesn't exist, create a new one
if (!(parsedDayISOString in this.OZCALENDARDAYS_STATE)) {
this.addFilePathToState(parsedDayISOString, file);
} else {
// if date exists and note is not in the date list
if (!(file.path in this.OZCALENDARDAYS_STATE[parsedDayISOString])) {
this.addFilePathToState(parsedDayISOString, file);
}
this.removeFilePathFromState(file.path);
if (cache && cache.frontmatter) {
let fm = cache.frontmatter;
for (let k of Object.keys(cache.frontmatter)) {
if (k === this.settings.yamlKey) {
let fmValue = fm[k];
let parsedDayISOString = dayjs(fmValue, this.settings.dateFormat).format('YYYY-MM-DD');
// If date doesn't exist, create a new one
if (!(parsedDayISOString in this.OZCALENDARDAYS_STATE)) {
this.addFilePathToState(parsedDayISOString, file.path);
} else {
// if date exists and note is not in the date list
if (!(file.path in this.OZCALENDARDAYS_STATE[parsedDayISOString])) {
this.addFilePathToState(parsedDayISOString, file.path);
}
}
}
}
this.calendarForceUpdate();
} else if (this.settings.dateSource === 'filename') {
// No action needed
}
this.calendarForceUpdate();
};
handleRename = (file: TFile, oldPath: string) => {
let changeFlag = false;
if (file instanceof TFile && file.extension === 'md') {
for (let k of Object.keys(this.OZCALENDARDAYS_STATE)) {
for (let ozItem of this.OZCALENDARDAYS_STATE[k]) {
if (ozItem.type === 'note' && ozItem.path === oldPath) {
if (this.settings.dateSource === 'yaml') {
ozItem.path = file.path;
ozItem.displayName = file.basename;
changeFlag = true;
} else if (this.settings.dateSource === 'filename') {
this.OZCALENDARDAYS_STATE[k] = this.OZCALENDARDAYS_STATE[k].filter((ozItem) => {
return !(ozItem.type === 'note' && ozItem.path === oldPath);
});
changeFlag = true;
}
}
}
}
let changeFlag = this.removeFilePathFromState(oldPath);
let changeFlag2 = this.scanTFileDate(file);
if (changeFlag || changeFlag2) this.calendarForceUpdate();
}
// Make sure that you scan the new file name for filename source
if (this.settings.dateSource === 'filename' && dayjs(file.name, this.settings.dateFormat).isValid()) {
let parsedDayISOString = dayjs(file.name, this.settings.dateFormat).format('YYYY-MM-DD');
if (parsedDayISOString in this.OZCALENDARDAYS_STATE) {
this.OZCALENDARDAYS_STATE[parsedDayISOString] = [
...this.OZCALENDARDAYS_STATE[parsedDayISOString],
fileToOZItem({ note: file }),
];
} else {
this.OZCALENDARDAYS_STATE[parsedDayISOString] = [fileToOZItem({ note: file })];
}
changeFlag = true;
}
// If change happened force update the component
if (changeFlag) this.calendarForceUpdate();
};
handleDelete = (file: TAbstractFile) => {
@ -277,23 +146,6 @@ export default class OZCalendarPlugin extends Plugin {
if (changeFlag) this.calendarForceUpdate();
};
handleCreate = (file: TAbstractFile) => {
if (file instanceof TFile && file.extension === 'md' && this.settings.dateSource === 'filename') {
if (dayjs(file.name, this.settings.dateFormat).isValid()) {
let parsedDayISOString = dayjs(file.name, this.settings.dateFormat).format('YYYY-MM-DD');
if (parsedDayISOString in this.OZCALENDARDAYS_STATE) {
this.OZCALENDARDAYS_STATE[parsedDayISOString] = [
...this.OZCALENDARDAYS_STATE[parsedDayISOString],
fileToOZItem({ note: file }),
];
} else {
this.OZCALENDARDAYS_STATE[parsedDayISOString] = [fileToOZItem({ note: file })];
}
}
this.calendarForceUpdate();
}
};
/* ------------ OTHER FUNCTIONS ------------ */
openOZCalendarLeaf = async (params: { showAfterAttach: boolean }) => {
@ -321,44 +173,27 @@ export default class OZCalendarPlugin extends Plugin {
let mdFiles = this.app.vault.getMarkdownFiles();
let OZCalendarDays: OZCalendarDaysMap = {};
for (let mdFile of mdFiles) {
if (this.settings.dateSource === 'yaml') {
// Get the file Cache
let fileCache = app.metadataCache.getFileCache(mdFile);
// Check if there is Frontmatter
if (fileCache && fileCache.frontmatter) {
let fm = fileCache.frontmatter;
// Check the FM keys vs the provided key by the user in settings
for (let k of Object.keys(fm)) {
if (k === this.settings.yamlKey) {
let fmValue = String(fm[k]);
// Parse the date with provided date format
let parsedDayJsDate = dayjs(fmValue, this.settings.dateFormat);
// Take only YYYY-MM-DD part fromt the date as String
let parsedDayISOString = parsedDayJsDate.format('YYYY-MM-DD');
// Check if it already exists
if (parsedDayISOString in OZCalendarDays) {
OZCalendarDays[parsedDayISOString] = [
...OZCalendarDays[parsedDayISOString],
fileToOZItem({ note: mdFile }),
];
} else {
OZCalendarDays[parsedDayISOString] = [fileToOZItem({ note: mdFile })];
}
}
}
}
} else if (this.settings.dateSource === 'filename') {
let dateFormatLength = this.settings.dateFormat.length;
if (mdFile.name.length >= dateFormatLength) {
if (dayjs(mdFile.name, this.settings.dateFormat).isValid()) {
let parsedDayISOString = dayjs(mdFile.name, this.settings.dateFormat).format('YYYY-MM-DD');
// Get the file Cache
let fileCache = app.metadataCache.getFileCache(mdFile);
// Check if there is Frontmatter
if (fileCache && fileCache.frontmatter) {
let fm = fileCache.frontmatter;
// Check the FM keys vs the provided key by the user in settings
for (let k of Object.keys(fm)) {
if (k === this.settings.yamlKey) {
let fmValue = (fm[k] as string).substring(0, this.settings.dateFormat.length);
// Parse the date with provided date format
let parsedDayJsDate = dayjs(fmValue, this.settings.dateFormat);
// Take only YYYY-MM-DD part fromt the date as String
let parsedDayISOString = parsedDayJsDate.format('YYYY-MM-DD');
// Check if it already exists
if (parsedDayISOString in OZCalendarDays) {
OZCalendarDays[parsedDayISOString] = [
...OZCalendarDays[parsedDayISOString],
fileToOZItem({ note: mdFile }),
mdFile.path,
];
} else {
OZCalendarDays[parsedDayISOString] = [fileToOZItem({ note: mdFile })];
OZCalendarDays[parsedDayISOString] = [mdFile.path];
}
}
}

View file

@ -22,12 +22,15 @@ export class CreateNoteModal extends Modal {
const headerEl = contentEl.createEl('div', { text: 'Create Note' });
headerEl.addClass('modal-title');
let inputCss = 'width: 100%; height: 2.5em;';
// Input El
contentEl.createEl('p', { text: 'File Name:' });
const fileNameInputEl = contentEl.createEl('input', { cls: 'oz-calendar-modal-inputel' });
const fileNameInputEl = contentEl.createEl('input');
fileNameInputEl.style.cssText = inputCss;
let defFileNamePref = this.plugin.settings.defaultFileNamePrefix;
if (defFileNamePref !== '') {
if (defFileNamePref !== '' && dayjs(new Date(), defFileNamePref, true).isValid()) {
fileNameInputEl.value = dayjs(this.destinationDate).format(defFileNamePref) + ' ';
}
@ -37,64 +40,47 @@ export class CreateNoteModal extends Modal {
let folderInputEl: HTMLInputElement = null;
if (this.plugin.settings.showDestinationFolderDuringCreate) {
contentEl.createEl('p', { text: 'Destination Folder:' });
folderInputEl = contentEl.createEl('input', { cls: 'oz-calendar-modal-inputel' });
folderInputEl = contentEl.createEl('input');
new FolderSuggest(folderInputEl);
folderInputEl.value = this.plugin.settings.defaultFolder;
folderInputEl.style.cssText = inputCss;
}
// Additional Space
let addSpace = contentEl.createEl('div', { cls: 'oz-calendar-modal-addspacediv ' });
let addSpace = contentEl.createEl('div');
addSpace.style.cssText = 'height: 20px;';
// Create - Cancel Buttons
const createButton = contentEl.createEl('button', {
text: 'Create Note',
cls: this.plugin.settings.newNoteCancelButtonReverse ? 'oz-calendar-modal-float-right' : '',
});
const cancelButton = contentEl.createEl('button', {
text: 'Cancel',
cls: this.plugin.settings.newNoteCancelButtonReverse ? '' : 'oz-calendar-modal-float-right',
});
const createButton = contentEl.createEl('button', { text: 'Create Note' });
const cancelButton = contentEl.createEl('button', { text: 'Cancel' });
cancelButton.style.cssText = 'float: right;';
cancelButton.addEventListener('click', () => {
thisModal.close();
});
const onClickCreateButton = async () => {
let newFileName = fileNameInputEl.value;
if (newFileName === '') {
if (newFileName !== '') {
let defFolderSrc = folderInputEl ? folderInputEl.value : this.plugin.settings.defaultFolder;
let defFolder = this.app.vault.getAbstractFileByPath(defFolderSrc);
if (defFolder && defFolder instanceof TFolder) {
// Default Text Preparation for File with YAML and Date
let defaultNewFileText = stripIndents`
---
${this.plugin.settings.yamlKey}: ${dayjs(this.destinationDate).format(
this.plugin.settings.dateFormat
)}
---
`;
// Create the MD File and close the modal
await createNewMarkdownFile(this.plugin, defFolder, newFileName, defaultNewFileText);
thisModal.close();
} else {
new Notice('Folder couldnt be found in the Vault');
}
} else {
new Notice('You didnt provide file name');
return;
}
if (newFileName.includes('/') && !this.plugin.settings.allowSlashhDuringCreate) {
new Notice('You can not have a slash (/) in file name');
return;
}
let defFolderSrc = folderInputEl ? folderInputEl.value : this.plugin.settings.defaultFolder;
let defFolder = this.app.vault.getAbstractFileByPath(defFolderSrc);
if (!defFolder || !(defFolder instanceof TFolder)) {
new Notice('Folder couldnt be found in the Vault');
return;
}
// Default Text Preparation for File with YAML and Date
let defaultNewFileText = stripIndents`
---
${this.plugin.settings.yamlKey}: ${dayjs(this.destinationDate).format(this.plugin.settings.dateFormat)}
---
`;
// Create the MD File and close the modal
await createNewMarkdownFile(
this.plugin,
defFolder as TFolder,
newFileName,
this.plugin.settings.dateSource === 'yaml' ? defaultNewFileText : ''
);
thisModal.close();
};
createButton.addEventListener('click', onClickCreateButton);

View file

@ -2,49 +2,28 @@ import OZCalendarPlugin from 'main';
import { PluginSettingTab, App, Setting } from 'obsidian';
import { FolderSuggest } from 'settings/suggestor';
export type OpenFileBehaviourType = 'new-tab' | 'new-tab-group' | 'current-tab' | 'obsidian-default';
export type SortingOption = 'name' | 'name-rev';
export type DateSourceOption = 'filename' | 'yaml';
export type NewNoteDateType = 'current-date' | 'active-date';
export type CalendarType = 'US' | 'ISO 8601';
export type OverflowBehaviour = 'scroll' | 'hide' | 'next-line';
export type OpenFileBehaviourType = 'new-tab' | 'new-tab-group' | 'current-tab';
export interface OZCalendarPluginSettings {
openViewOnStart: boolean;
calendarType: CalendarType;
dateSource: DateSourceOption;
yamlKey: string;
dateFormat: string;
defaultFolder: string;
defaultFileNamePrefix: string;
fixedCalendar: boolean;
showDestinationFolderDuringCreate: boolean;
allowSlashhDuringCreate: boolean;
openFileBehaviour: OpenFileBehaviourType;
sortingOption: SortingOption;
newNoteDate: NewNoteDateType;
newNoteCancelButtonReverse: boolean;
fileNameOverflowBehaviour: OverflowBehaviour;
showWeekNumbers: boolean;
}
export const DEFAULT_SETTINGS: OZCalendarPluginSettings = {
openViewOnStart: true,
calendarType: 'ISO 8601',
dateSource: 'yaml',
yamlKey: 'created',
dateFormat: 'YYYY-MM-DD hh:mm:ss',
defaultFolder: '/',
defaultFileNamePrefix: 'YYYY-MM-DD',
fixedCalendar: true,
showDestinationFolderDuringCreate: true,
allowSlashhDuringCreate: false,
openFileBehaviour: 'current-tab',
sortingOption: 'name',
newNoteDate: 'current-date',
newNoteCancelButtonReverse: false,
fileNameOverflowBehaviour: 'hide',
showWeekNumbers: false,
};
export class OZCalendarPluginSettingsTab extends PluginSettingTab {
@ -97,42 +76,11 @@ export class OZCalendarPluginSettingsTab extends PluginSettingTab {
});
});
new Setting(containerEl)
.setName('Calendar Type')
.setDesc(
`
Select the calendar type to be displayed. While the week in the US type starts from Sunday,
in the ISO 8601 type, the week starts from Monday`
)
.addDropdown((dropdown) => {
dropdown
.addOption('ISO 8601', 'ISO 8601')
.addOption('US', 'US')
.setValue(this.plugin.settings.calendarType)
.onChange((newValue: CalendarType) => {
this.plugin.settings.calendarType = newValue;
this.plugin.saveSettings();
this.plugin.calendarForceUpdate();
});
});
new Setting(containerEl)
.setName('Show Week Numbers')
.setDesc('Enable if you want to have week numbers within the calendar view')
.addToggle((toggle) => {
toggle.setValue(this.plugin.settings.showWeekNumbers).onChange((newValue) => {
this.plugin.settings.showWeekNumbers = newValue;
this.plugin.saveSettings();
this.plugin.calendarForceUpdate();
});
});
new Setting(containerEl)
.setName('Open File Behaviour')
.setDesc('Select the behaviour you want to have when you click on file name in the calendar view')
.addDropdown((dropdown) => {
dropdown
.addOption('obsidian-default', "Obsidian's Default")
.addOption('new-tab', 'Open in a New Tab')
.addOption('new-tab-group', 'Open in a New Tab Group')
.addOption('current-tab', 'Open in the Active Tab')
@ -143,22 +91,7 @@ export class OZCalendarPluginSettingsTab extends PluginSettingTab {
});
});
new Setting(containerEl)
.setName('File List Sorting')
.setDesc('Select the sorting behaviour in the file list')
.addDropdown((dropdown) => {
dropdown
.addOption('name', 'File Name (A to Z)')
.addOption('name-rev', 'File Name (Z to A)')
.setValue(this.plugin.settings.sortingOption)
.onChange((newValue: SortingOption) => {
this.plugin.settings.sortingOption = newValue;
this.plugin.saveSettings();
this.plugin.calendarForceUpdate();
});
});
containerEl.createEl('h2', { text: 'YAML, File Name and Date Format Settings' });
containerEl.createEl('h2', { text: 'YAML and Date Format' });
containerEl.createEl('p', {
text: `
@ -169,35 +102,6 @@ export class OZCalendarPluginSettingsTab extends PluginSettingTab {
});
new Setting(containerEl)
.setName('Date Source')
.setDesc(
`Select the date source to be used in each folder. It can be either YAML Key or File Name.
Depending on what you provide within the date format, it will try to parse the date source.`
)
.addDropdown((dropdown) => {
dropdown
.addOption('filename', 'File Name')
.addOption('yaml', 'YAML Key')
.setValue(this.plugin.settings.dateSource)
.onChange((newValue: DateSourceOption) => {
this.plugin.settings.dateSource = newValue;
this.plugin.saveSettings();
this.plugin.OZCALENDARDAYS_STATE = this.plugin.getNotesWithDates();
this.plugin.calendarForceUpdate();
// If YAML selected, show the YAML key below, or hide if changed back to filename
let yamlKeySettingEl = document.querySelector('.oz-calendar-setting-yaml-key-value');
if (yamlKeySettingEl) {
if (newValue === 'filename') {
yamlKeySettingEl.addClass('oz-calendar-custom-hidden');
} else {
yamlKeySettingEl.removeClass('oz-calendar-custom-hidden');
}
}
});
});
let yamlKeySetting = new Setting(containerEl)
.setClass('oz-calendar-setting-yaml-key-value')
.setName('YAML Key')
.setDesc('Set the YAML Key that should be used for displaying in the calendar')
.addText((text) => {
@ -207,16 +111,9 @@ export class OZCalendarPluginSettingsTab extends PluginSettingTab {
});
});
if (this.plugin.settings.dateSource === 'filename') yamlKeySetting.setClass('oz-calendar-custom-hidden');
new Setting(containerEl)
.setName('Date Format')
.setDesc(
`Set the Date format you are using within the YAML key or File Name provided above.
If you are using File Name, make sure that you dont have any special characters since Obsidian doesnt
support special characters in the file name like colon. Reload the plugin using the following button
in case you change this value`
)
.setDesc('Set the Date format you are using within the YAML key provided above')
.addText((text) => {
text.setValue(this.plugin.settings.dateFormat).onChange((newValue) => {
this.plugin.settings.dateFormat = newValue;
@ -236,35 +133,7 @@ export class OZCalendarPluginSettingsTab extends PluginSettingTab {
containerEl.createEl('h2', { text: 'New Note Settings' });
containerEl.createEl('p', {
text: `
The plugin will add the YAML key and date to the newly created note using the date format provided above
if Date Source is YAML. However, auto YAML key generation for the notes is going to be disabled if you use
File Name as date source.
`,
cls: 'setting-item-description',
});
new Setting(containerEl)
.setName('New Note Date')
.setDesc(
`
Define the default behaviour for new note button if it should create under the active date or current date (today).
This setting will drive the date for the YAML Key value and File Name.
`
)
.addDropdown((dropdown) => {
dropdown
.addOption('active-date', 'Active Date (Selected)')
.addOption('current-date', 'Current Date (Today)')
.setValue(this.plugin.settings.newNoteDate)
.onChange((newValue: NewNoteDateType) => {
this.plugin.settings.newNoteDate = newValue;
this.plugin.saveSettings();
});
});
new Setting(containerEl)
new Setting(this.containerEl)
.setName('Default Folder Location')
.setDesc('Select the default folder, under which the new files should be saved when use plugin + icon')
.addSearch((cb) => {
@ -306,35 +175,6 @@ export class OZCalendarPluginSettingsTab extends PluginSettingTab {
});
});
new Setting(containerEl)
.setName('Allow to provide slash during the file creation')
.setDesc(
`
Enable this option if you want to allow file creation modal to allow slash (/) in the filename, which will help creating a folder.
i.e. if this option is enabled and you provide an input like Folder1/File1, this will create Folder1 and place File1 under it. If
the folder exists, the file will be placed under the existing folder. This will respect the default folder location and create the
new folder as a subfolder under the default one.
`
)
.addToggle((toggle) => {
toggle.setValue(this.plugin.settings.allowSlashhDuringCreate).onChange((newValue) => {
this.plugin.settings.allowSlashhDuringCreate = newValue;
this.plugin.saveSettings();
});
});
new Setting(containerEl)
.setName('Reverse direction of Cancel and New Note Buttons')
.setDesc(
`Enable this setting to change the direction of Cancel and New Note buttons within the New Note Creation Modal`
)
.addToggle((toggle) => {
toggle.setValue(this.plugin.settings.newNoteCancelButtonReverse).onChange((newValue) => {
this.plugin.settings.newNoteCancelButtonReverse = newValue;
this.plugin.saveSettings();
});
});
containerEl.createEl('h2', { text: 'Style Settings' });
containerEl.createEl('p', {
@ -356,21 +196,5 @@ export class OZCalendarPluginSettingsTab extends PluginSettingTab {
this.plugin.calendarForceUpdate();
});
});
new Setting(containerEl)
.setName('File Names Overflow Behaviour')
.setDesc('Change the default behaviour for file names when they dont fit to the view')
.addDropdown((dropdown) => {
dropdown
.addOption('hide', 'Hide Overflow')
.addOption('scroll', 'Scroll Overflow')
.addOption('next-line', 'Show Overflow in the Next Line')
.setValue(this.plugin.settings.fileNameOverflowBehaviour)
.onChange((newValue: OverflowBehaviour) => {
this.plugin.settings.fileNameOverflowBehaviour = newValue;
this.plugin.saveSettings();
this.plugin.calendarForceUpdate();
});
});
}
}

View file

@ -1,29 +1,3 @@
import { TFile } from 'obsidian';
export type OZNote = {
type: 'note';
displayName: string;
path: string;
};
export type OZReminder = {
type: 'task' | 'periodic';
displayName: string;
date: string;
};
type OZItem = OZNote | OZReminder;
export interface OZCalendarDaysMap {
[key: string]: OZItem[];
[key: string]: string[];
}
export type DayChangeCommandAction = 'next-day' | 'previous-day' | 'today';
export const fileToOZItem = (params: { note: TFile }): OZItem => {
return {
type: 'note',
displayName: params.note.basename,
path: params.note.path,
};
};

View file

@ -1,8 +1,8 @@
import { ItemView, WorkspaceLeaf } from 'obsidian';
import React from 'react';
import ReactDOM from 'react-dom';
import OZCalendarPlugin from './main';
import MyCalendar from './components/calendar';
import { createRoot, Root } from 'react-dom/client';
export const VIEW_TYPE = 'oz-calendar';
export const VIEW_DISPLAY_TEXT = 'OZ Calendar';
@ -10,7 +10,6 @@ export const ICON = 'OZCAL_ICON';
export class OZCalendarView extends ItemView {
plugin: OZCalendarPlugin;
root: Root;
constructor(leaf: WorkspaceLeaf, plugin: OZCalendarPlugin) {
super(leaf);
@ -34,12 +33,11 @@ export class OZCalendarView extends ItemView {
}
destroy() {
if (this.root) this.root.unmount();
ReactDOM.unmountComponentAtNode(this.contentEl);
}
async onOpen() {
this.destroy();
this.root = createRoot(this.contentEl)
this.root.render(<MyCalendar plugin={this.plugin} />);
ReactDOM.render(<MyCalendar plugin={this.plugin} />, this.contentEl);
}
}

View file

@ -14,21 +14,7 @@ settings:
-
id: oz-calendar-selected-daycolor
title: Selected Day Text Color
description: Set the color of selected day in the month view, defaulted to text-normal
type: variable-color
format: hex
default: '#'
-
id: oz-calendar-current-day-color
title: Current Day (Today) Text Color
description: Set the color of the current day in the month view
type: variable-color
format: hex
default: '#'
-
id: oz-calendar-selected-day-background
title: Selected Day Background Color
description: Set the color of selected day background in the month view, defaulted to the interactive-accent
description: Set the color of selected day in the month view, defaulted to the interactive-accent
type: variable-color
format: hex
default: '#'
@ -39,23 +25,13 @@ settings:
type: variable-color
format: hex
default: '#'
-
id: oz-calendar-weeknr-date-color
title: Week Number Text Color
description: Set the color of week numbers, defaulted to the interactive-accent
type: variable-color
format: hex
default: '#'
*/
.theme-light,
.theme-dark {
--oz-calendar-weekend-color: #f76a6a;
--oz-calendar-selected-daycolor: var(--text-normal);
--oz-calendar-selected-day-background: var(--interactive-accent);
--oz-calendar-header-date-color: var(--interactive-accent);
--oz-calendar-current-day-color: #74dd58;
--oz-calendar-weeknr-date-color: var(--color-accent-2);
--oz-calendar-selected-daycolor: var(----interactive-accent);
--oz-calendar-header-date-color: var(----interactive-accent);
}
.oz-cal-coffee-div,
@ -72,20 +48,10 @@ settings:
fill: var(--icon-color) !important;
}
.oz-calendar-plugin-view {
min-height: 100%;
display: flex;
flex-direction: column;
}
.oz-calendar-plugin-view .react-calendar__tile.react-calendar__month-view__days__day:hover {
background: var(--background-secondary-alt);
}
.oz-calendar-plugin-view .react-calendar__tile--active {
background-color: var(--oz-calendar-selected-day-background) !important;
}
.oz-calendar-plugin-view .react-calendar button:enabled:hover {
cursor: pointer;
}
@ -166,10 +132,10 @@ settings:
}
.oz-calendar-notelist-container {
display: flex;
flex-direction: row;
justify-content: space-between;
display: block;
padding: 5px;
flex: 1;
vertical-align: middle;
}
.oz-calendar-nav-action-plus {
@ -215,6 +181,11 @@ settings:
opacity: 0.6;
}
.oz-calendar-notelist-container {
display: block;
padding: 5px;
}
.oz-calendar-note-line {
padding-top: 3px;
padding-bottom: 3px;
@ -246,11 +217,6 @@ settings:
margin-right: 3px;
}
.oz-calendar-plugin-today abbr {
color: var(--oz-calendar-current-day-color);
font-weight: bold;
}
/* START - Fixed Calendar Except Note List - Scroll */
.oz-calendar-plugin-view.fixed {
@ -261,7 +227,7 @@ settings:
}
.oz-calendar-plugin-view.fixed .react-calendar {
height: 295px;
height: 255px;
}
.oz-calendar-plugin-view.fixed #oz-calendar-divider {
@ -278,44 +244,4 @@ settings:
vertical-align: top;
}
.oz-calendar-plugin-view .react-calendar__month-view__weekNumbers {
display: block !important;
color: var(--oz-calendar-weeknr-date-color);
flex-basis: auto !important;
background-color: var(--background-modifier-cover);
font-size: var(--nav-item-size);
}
/* END - Fixed Calendar */
.oz-calendar-modal-inputel {
width: 100%;
height: 2.5em;
}
.oz-calendar-modal-addspacediv {
height: 20px;
}
.oz-calendar-modal-float-right {
float: right;
}
.oz-calendar-custom-hidden {
display: none !important;
}
.oz-calendar-note-line {
color: var(--text-muted);
}
.oz-calendar-overflow-scroll {
overflow: scroll;
white-space: nowrap;
}
.oz-calendar-overflow-hide {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}

View file

@ -1,36 +1,4 @@
{
"0.3.4": "0.15.0",
"0.3.3": "0.15.0",
"0.3.2": "0.15.0",
"0.3.1": "0.15.0",
"0.3.0": "0.15.0",
"0.2.9": "0.15.0",
"0.2.8": "0.15.0",
"0.2.7": "0.15.0",
"0.2.6": "0.15.0",
"0.2.5": "0.15.0",
"0.2.4": "0.15.0",
"0.2.3": "0.15.0",
"0.2.2": "0.15.0",
"0.2.1": "0.15.0",
"0.2.0": "0.15.0",
"0.1.9": "0.15.0",
"0.1.8": "0.15.0",
"0.1.7": "0.15.0",
"0.1.6": "0.15.0",
"0.1.5": "0.15.0",
"0.1.4": "0.15.0",
"0.1.3": "0.15.0",
"0.1.2": "0.15.0",
"0.1.1": "0.15.0",
"0.1.0": "0.15.0",
"0.0.9": "0.15.0",
"0.0.8": "0.15.0",
"0.0.7": "0.15.0",
"0.0.6": "0.15.0",
"0.0.5": "0.15.0",
"0.0.4": "0.15.0",
"0.0.3": "0.15.0",
"0.0.2": "0.15.0",
"0.0.1": "0.15.0",
"0.0.0": "0.15.0"