diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..81f3ec3
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,10 @@
+# top-most EditorConfig file
+root = true
+
+[*]
+charset = utf-8
+end_of_line = lf
+insert_final_newline = true
+indent_style = tab
+indent_size = 4
+tab_width = 4
diff --git a/.eslintignore b/.eslintignore
new file mode 100644
index 0000000..e019f3c
--- /dev/null
+++ b/.eslintignore
@@ -0,0 +1,3 @@
+node_modules/
+
+main.js
diff --git a/.eslintrc b/.eslintrc
new file mode 100644
index 0000000..0807290
--- /dev/null
+++ b/.eslintrc
@@ -0,0 +1,23 @@
+{
+ "root": true,
+ "parser": "@typescript-eslint/parser",
+ "env": { "node": true },
+ "plugins": [
+ "@typescript-eslint"
+ ],
+ "extends": [
+ "eslint:recommended",
+ "plugin:@typescript-eslint/eslint-recommended",
+ "plugin:@typescript-eslint/recommended"
+ ],
+ "parserOptions": {
+ "sourceType": "module"
+ },
+ "rules": {
+ "no-unused-vars": "off",
+ "@typescript-eslint/no-unused-vars": ["error", { "args": "none" }],
+ "@typescript-eslint/ban-ts-comment": "off",
+ "no-prototype-builtins": "off",
+ "@typescript-eslint/no-empty-function": "off"
+ }
+ }
\ No newline at end of file
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 0000000..2a32bfe
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,34 @@
+name: Release Obsidian plugin
+
+on:
+ push:
+ tags:
+ - "*"
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: Use Node.js
+ uses: actions/setup-node@v3
+ with:
+ node-version: "18.x"
+
+ - name: Build plugin
+ run: |
+ npm install
+ npm run build
+
+ - name: Create release
+ env:
+ GITHUB_TOKEN: ${{ secrets.GH_PAT }}
+ run: |
+ tag="${GITHUB_REF#refs/tags/}"
+
+ gh release create "$tag" \
+ --title="$tag" \
+ --draft \
+ main.js manifest.json styles.css
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..386ac2b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,22 @@
+# vscode
+.vscode
+
+# Intellij
+*.iml
+.idea
+
+# npm
+node_modules
+
+# Don't include the compiled main.js file in the repo.
+# They should be uploaded to GitHub releases instead.
+main.js
+
+# Exclude sourcemaps
+*.map
+
+# obsidian
+data.json
+
+# Exclude macOS Finder (System Explorer) View States
+.DS_Store
diff --git a/.npmrc b/.npmrc
new file mode 100644
index 0000000..b973752
--- /dev/null
+++ b/.npmrc
@@ -0,0 +1 @@
+tag-version-prefix=""
\ No newline at end of file
diff --git a/README.md b/README.md
index 815f395..b677c82 100644
--- a/README.md
+++ b/README.md
@@ -15,15 +15,17 @@ All Obsidian and Task Plugin users love the program. What has been set up with t
## Setup
1. Install "Dataview Plugin" from the external plugins
-2. Create a new folder called "tasksCalendar" or any other name and paste the files "view.js" and "view.css" into it
![Tree Demo](https://user-images.githubusercontent.com/59178587/203789303-4474847e-ab84-4f33-8665-c17ca887ec79.png)
3. Create a new note or edit an existing one and add the following code line:
````
- ```dataviewjs
- await dv.view("tasksCalendar", {pages: "", view: "month", firstDayOfWeek: "1", options: "style1"})
+ ```Calendar
+ pages: ""
+ view: month
+ firstDayOfWeek: 1
+ options: style1
```
````
@@ -44,7 +46,7 @@ pages: ""
Get all tasks from all notes in obsidian.
```
-pages: '"Task Management/Work"'
+pages: "Task Management/Work"
```
Set a custom folder to get tasks from.
@@ -60,24 +62,24 @@ It is also possible to define complex queries. These must start with `dv.pages`
### view:
```
-view: "list"
-view: "month"
-view: "week"
+view: list
+view: month
+view: week
```
With the view parameter you can set the default calendar view.
### firstDayOfWeek:
```
-firstDayOfWeek: "1"
-firstDayOfWeek: "0"
+firstDayOfWeek: 1
+firstDayOfWeek: 0
```
Set monday (1) or sunday (0) as first day of week
### options:
```
-options: "style1"
+options: style1
```
You have multiple options to personalize your Tasks-Calendar. The absolutelely must have is to set a custom week view style (style1, style2, ...) as your default week view style. However, you can switch between the individual styles at any time in the calendar itself by clicking the week view button again if this view is active.
@@ -86,58 +88,58 @@ You have multiple options to personalize your Tasks-Calendar. The absolutelely m
But that's not all. With the options parameter you can hide things you don't need or like, get a mini version of the calendar and many more...
```
-options: "noIcons"
+options: noIcons
```
Hide the task icons in front of each task.
```
-options: "noProcess"
+options: noProcess
```
By default the Tasks-Calendar show up tasks with a start- and a due-date on all days between these two like a calendar app displays all-day events across all days from the first to the last day. If you don't like this, you can turn it off with the `noProcess` option.
```
-options: "noDailyNote"
+options: noDailyNote
```
Hide daily notes inside calendar
Some users do not use the Task plugin, but work mainly with daily notes. To enable these users to use the functionality of this calendar, all tasks from daily notes are displayed on the respective date of the daily note. As some task plugin users may also work with daily notes, some may find it annoying to see them in the calendar as well between all Task plugin stuff. With the option `noDailyNote` you can hide all tasks (without any Task plugin date syntax) from your calendar.
```
-options: "noCellNameEvent"
+options: noCellNameEvent
```
By default you can click on each cell name to jump directly into the daily note. If no daily note with this date exist, a new one will be created. This is nice for hardcore daily note users, but for others it could be annoying. To prevent unintentional execution you can disable the cell name click-events with the option `noCellNameEvent`.
```
-options: "mini"
+options: mini
```
Reduces the calendar width, height and font sizes to a more compact format. This can be used to embed the calendar into a complex sidebar in Obsidian.
On mobile devices, the font size is automatically reduced (on some views) because the limited screen size.
```
-options: "noWeekNr"
+options: noWeekNr
```
Hide the week number in front of each week-wrapper inside the month calendar. After deactivation, it is unfortunately no longer possible to jump directly to a desired week.
```
-options: "noFilename"
+options: noFilename
```
Hides the task header line with the note file name
```
-options: "lineClamp1"
-options: "lineClamp2"
-options: "lineClamp3"
-options: "noLineClamp"
+options: lineClamp1
+options: lineClamp2
+options: lineClamp3
+options: noLineClamp
```
Set a line clamp from 1-3 inside your displayed tasks. By default 1 line is set. Alternative you can disable line clamp and show full task description text.
```
-options: "noLayer"
+options: noLayer
```
The back layer of the grid with the month or week information can be hidden with this.
```
-options: "noOverdueDays"
+options: noOverdueDays
```
You can use this option to hide the overdue days flag on overdue tasks.
@@ -145,15 +147,15 @@ You can use this option to hide the overdue days flag on overdue tasks.
#### dailyNoteFolder:
```
-dailyNoteFolder: "MyCustomFolder"
-dailyNoteFolder: "Inbox/Daily Notes/Work"
+dailyNoteFolder: MyCustomFolder
+dailyNoteFolder: Inbox/Daily Notes/Work
```
This parameter must only be specified if this is to be used. Here you can define a custom folder path for the daily notes if they should not be saved in the default folder for new files. Of course, folder structures with several levels can also be defined here. This paramter
#### dailyNoteFormat:
```
-dailyNoteFormat: "YYYY, MMMM DD - dddd"
-dailyNoteFormat: "YYYY-[W]ww"
+dailyNoteFormat: YYYY, MMMM DD - dddd
+dailyNoteFormat: YYYY-[W]ww
```
This parameter must only be specified if this is to be used. Without this parameter the default format "YYYY-MM-DD" is used to identify your daily notes. You can set a custom format with a limited base set of characters: Y M D [W] ww d . , - : (SPACE)
@@ -161,29 +163,47 @@ This parameter must only be specified if this is to be used. Without this parame
Month: 2022 - December
```
-view: "month"
-startPosition: "2022-12"
+view: month
+startPosition: 2022-12
```
Week: 2022 - W50
```
-view: "week"
-startPosition: "2022-50"
+view: week
+startPosition: 2022-50
```
This parameter is optional and can be used to set a custom month or week to give focus after load. The default format on month view is `YYYY-MM`and on week view `YYYY-ww`. The first 4 digits represents the year and the last 1-2 digits represents the month or the week. Both must be separated with a minus character.
#### globalTaskFilter:
```
-globalTaskFilter: "#task"
+globalTaskFilter: #task
```
This parameter must only be specified if this is to be used. Set a global task filter to hide from task text/description inside tasks-calendar.
#### css:
```
-css: ".tasksCalendar.style4[view='week'] .grid { height: 300px !important }"
+css: .tasksCalendar.style4[view='week'] .grid { height: 300px !important }
```
Now you can write custom css rules inside a css parameter. Please use the developer console to identify the elements classes! Each style string should start with .tasksCalendar to avoid css conflicts!
+#### taskCountOnly
+```
+taskCountOnly: true
+```
+This parameter displays only the number of tasks on each days
+
+#### disableRecurrence
+```
+disableRecurrence: true
+```
+Now you can see the recurring tasks every days they will appear in the future, not only the current day, if you want to disable this new feature set this parameter to `true`
+
+#### hideFileWithProps
+```
+hideFileWithProps: Archived, Handled By
+```
+This filter will remove the tasks that are not checked and present in a file with a mentionned property, as `Archived` or `Handled By` in this example
+
---
## Note colors and icon
@@ -191,9 +211,9 @@ In each note file you can define custom "color" and "icon" to show up in the cal
```
---
-color: "#bf5af2"
-textColor: "#000000"
-icon: "❤️"
+color: #bf5af2
+textColor: #000000
+icon: ❤️
---
```
@@ -217,3 +237,315 @@ On the upper right corner is statistic button which opens a detailed list of all
Through a meaningful icon and a counter, you can quickly get an overview of incompleted tasks within the selected month/week without opening the pop-up window.
![Focus Demo](https://user-images.githubusercontent.com/59178587/203786131-6ddf1389-8b66-4f3c-9d7a-121c5fe38540.png)
+
+
+# Taskido: Obsidian-Tasks-Timeline
+#### A custom view build with [Obsidian-Dataview](https://github.com/blacksmithgu/obsidian-dataview) to display tasks from [Obsidian-Tasks](https://github.com/obsidian-tasks-group/obsidian-tasks) and from your daily notes in a highly customisable timeline
+
+
+
+- All your tasks in a clean and simple timeline view
+- Focus today and filter to do, overdue or unplanned tasks
+- Quick add new tasks without having to open notes
+- Forward tasks from past days to today
+- Relative dates for quicker classification
+- Scratch tasks to your inbox for better time management
+- Custom colors for all your tags and notes
+
+---
+
+## Story
+Many Obsidian and Task Plugin users need to build certain queries using the Dataview Plugin, or with the queries included in the Task Plugin. These queries then allow the user to keep track of certain previously defined tasks. The visual representation of the query result is very plain and rigid, as are the customisation options for the display. The aim of this customised view is to make almost all of the user's tinkered queries redundant with an all-round solution.
+
+Although I initially developed the Obsidian Tasks Calendar, I now work exclusively with the Timeline, as it shows me all the information at any given time without overwhelming me.
+
+---
+
+## Setup
+1. Install "Dataview Plugin" from the external plugins
+2. Create a new folder called "Taskido" or any other name and paste the files "view.js" and "view.css" into it
+3. Create a new note or edit an existing one and add the following code line:
+
+ ````
+ ```Taskido
+ pages:""
+ ```
+ ````
+
+ If you paste the main files (js/css) into another folder then "Taskido", you have to replace the name between the first quotation marks.
+
+ 4. There are more parameters to customize the look and feel of Taskido but there aren't necessary.
+
+ Parameters must be declared in the curly bracket and all parameters are separated by a comma. The name of the parameter is followed by a colon, a space and quotes in which the corresponding value of the parameter is declared.
+
+ The options parameter is the only parameter to which multiple values (separated by a space (no comma)) can be assigned. The values declared in options function as style classes within the CSS (Cascading Style Sheet) and primarily serve to hide elements when they are not needed.
+
+ True and false values are always declared without quotes.
+
+ All this together results in the following structure:
+
+ ````
+ ```Taskido
+ parameter: "value"
+ parameter: "value"
+ parameter: true
+ parameter: "value value value value"
+ ```
+
+ For example...
+
+ ```Taskido
+ pages: ""
+ select: "Task Management/Inbox.md"
+ inbox: "Task Management/Inbox.md"
+ dailyNoteFolder: "Daily Notes"
+ forward:true, options: ""
+ ```
+ ````
+
+---
+
+## Required parameter
+
+### pages:
+For help and instruction take a look here [Dataview Help](https://blacksmithgu.github.io/obsidian-dataview/api/code-reference/#dvpagessource)
+```
+pages: ""
+```
+Get all tasks from all notes in obsidian.
+
+```
+pages: '"Task Management/Work"'
+```
+Set a custom folder to get tasks from.
+
+The dv.pages command is the same and works exactly the same like in dataview-plugin.
+
+```
+pages: "dv.pages().file.tasks.where(t => t.tags.includes('#Pierre'))"
+pages: "dv.pages().file.tasks.where(t=>!t.checked && t.header.subpath != 'Log')"
+pages: "dv.pages().file.where(f=>f.tags.includes('#ToDo') || f.tags.includes('#Task')).where(f=>f.folder != 'Inbox').tasks"
+```
+It is also possible to define complex queries. These must start with `dv.pages` and output tasks as a result.
+
+---
+
+## Optional parameters
+```
+options: "noCounters"
+options: "noQuickEntry"
+options: "noYear"
+options: "noRelative"
+options: "noRepeat"
+options: "noPriority"
+options: "noTag"
+options: "noFile"
+options: "noHeader"
+options: "noInfo"
+options: "noDone"
+```
+With this options you can hide some elements which they do not need, or which disturb.
+
+### Combining options
+```
+options: "noCounters noQuickEntry noInfo"
+```
+All options can be combined with each other as desired.
+
+### Focus/Filter options
+```
+options: "todayFocus"
+```
+With this option you can set default focus on today after open the timeline.
+
+```
+options: "todoFilter"
+options: "overdueFilter"
+options: "unplannedFilter"
+```
+
+With this options you can set a default filter after open the timeline.
+
+### dailyNoteFolder:
+```
+dailyNoteFolder: "MyCustomFolder"
+dailyNoteFolder: "Inbox/Daily Notes/Work"
+```
+Here you can set a custom folder path for the daily notes if they should not be saved in the default folder for new files. Of course, folder structures with several levels can also be defined here.
+
+### dailyNoteFormat:
+```
+dailyNoteFormat: "YYYY, MMMM DD - dddd"
+dailyNoteFormat: "YYYY-[W]ww"
+```
+You can set a custom format with a limited base set of characters: Y M D [W] ww d . , - : (SPACE). Without this parameter the default format "YYYY-MM-DD" is used to identify your daily notes.
+
+### section:
+```
+section: "## Tasks"
+```
+You can set the section within the notes file to append new tasks. The example above will append tasks in your notes under the section `## Tasks`. The match should be exact. Without this parameter, new tasks are appended at the end of the file.
+
+### globalTaskFilter:
+```
+globalTaskFilter: "#task"
+```
+Set a global task filter to hide from task text/description inside tasks-calendar.
+
+### sort:
+```
+sort: "t=>t.order"
+sort: "t=>t.text"
+sort: "t=>t.completed"
+sort: "t=>t.priority"
+```
+With the sort paramter you can set your personal sort algorithm to sort your tasks inside a day.
+
+### forward:
+```
+forward: true
+```
+This parameter carry forward tasks from past and display them on the current date.
+
+### dateFormat:
+```
+dateFormat: "YYYY-MM-DD"
+dateFormat: "ddd, MMM D"
+```
+With this parameter you can set a custom date format with moment.js syntax. By default the format "ddd, MMM D" is set.
+
+### select:
+```
+select: "Task Management/Inbox.md"
+```
+With this parameter you can set a default file selection for the quick entry panel. By default Taskido select the daily note from today, even if this does not yet exist. By pushing a task into it, the daily note is created automatically.
+
+### inbox:
+```
+inbox: "Task Management/Inbox.md"
+```
+With this parameter you can set a custom file as your Inbox to scratch tasks first before moving them into the correct note file (GTD). All tasks from within this file are listed on today, even if the tasks have not yet been assigned a date at all. In this way, tasks can be recorded quickly without having to be fully formulated. So you can return to your actual activities and complete the follow-up of the tasks at a later and more appropriate time.
+
+### taskFiles:
+```
+taskFiles: "" => files with uncompleted tasks (set by default without declaring this parameter)
+taskFiles: "#taskido" => files with tag #taskido
+taskFiles: '"Task Management/Work"' => files in folder Task Management
+taskFiles: '("Task Management" and -"Task Management/Archive")' => folder Task Management without folder Task Management/Archive
+taskFiles: '"Task Management" or #taskido' files in folder Task Management or files with tag #taskido
+```
+With this parameter you can select files to show up inside quick entry select box.
+
+---
+
+## Note colors
+In each note file you can set a custom "color" to show up in the calendar. You only need to add the following metadata to the first line of your note.
+
+
+
+The color should be hex in quotation marks to work properly.
+
+
+
+---
+
+## Tag colors
+You can set a custom color for all your tags displayed inside Taskido. Here I'm using the nesting tag feature to implement this. The first tag (root-node) is used as hex-color and the second tag after the slash is your main tag:
+
+ `#0a84ff/demo`
+
+If Taskido can identify the first tag as a hex-color, your tag get this as custom var(--tag-color) and var(--tag-background). The hex-color isn't visible on the displayed tag itself because it will be replaced.
+
+The tag-autocomplete functionality inside Obsidian makes it possible to quickly find and re-use an existing tag without typing the hex-color first. This is realy cool and I hope the Obsidian founders will implement this in future.
+
+
+
+
+
+**Small Color Palette**
+```
+#ff443a/red #ff9d0a/orange #ffd60a/yellow #30d158/green #66d4cf/mint #40c8e0/teal #64d3ff/cyan #0a84ff/blue #5e5ce6/indigo #bf5af2/purple #ff375f/pink #ac8f68/brown
+```
+---
+### disableRecurrence
+```
+disableRecurrence: true
+```
+Now you can see the recurring tasks every days they will appear in the future, not only the current day, if you want to disable this new feature set this parameter to `true`
+
+---
+### hideFileWithProps
+```
+hideFileWithProps: Archived, Handled By
+```
+This filter will remove the tasks that are not checked and present in a file with a mentionned property, as `Archived` or `Handled By` in this example
+
+---
+### numberOfDays
+```
+numberOfDays: 5
+```
+Choose the number of days you want to view in the future in your timeline
+
+---
+
+## Filter
+A small separation give focus on today. Three info boxes (To Do, Overdue, Unplanned
+) give you all necessary informations to do your best on today. By clicking on each box, your selected tasks get filtered. By clicking on the "Today" header you can also hide all other days from timeline.
+
+
+
+
+---
+
+## Quick entry panel
+
+
+
+Quick entry panel to write new tasks and push directly into custom note file. All currently used notes with active tasks were listed in a select box on top of the quick entry panel. The todays daily note is pinned to that list too, even if this file doesn't exist at that moment. If you push a task to that file, the file will be created at that moment. In order to simplify the recording of tasks, some autotext shortcuts have been programmed. The following text snippets will be replaced automatically to Task Plugin syntax:
+
+### Symbol snippets
+```
+due > 📅
+start > 🛫
+scheduled > ⏳
+done > ✅
+high > ⏫
+medium > 🔼
+low > 🔽
+repeat > 🔁
+recurring > 🔁
+```
+
+### Date snippets
+
+To get yesterday, today, or tomorrow, simply type...
+```
+today
+tomorrow
+yesterday
+```
+
+If you would like to get the date of the next upcoming weekday by name...
+```
+monday
+tuesday
+wednesday
+thursday
+friday
+saturday
+sunday
+```
+
+Relative dates in the below format can also be converted into YYYY-MM-DD format...
+```
+in X days/weeks/month/years
+
+for example:
+
+in 3 weeks
+or
+in 1 year
+```
+
+---
\ No newline at end of file
diff --git a/demo_file.md b/demo_file.md
new file mode 100644
index 0000000..c5e78b5
--- /dev/null
+++ b/demo_file.md
@@ -0,0 +1,6 @@
+```Calendar
+pages: ""
+view: month
+firstDayOfWeek: 1
+options: style1
+```
diff --git a/esbuild.config.mjs b/esbuild.config.mjs
new file mode 100644
index 0000000..a5de8b8
--- /dev/null
+++ b/esbuild.config.mjs
@@ -0,0 +1,49 @@
+import esbuild from "esbuild";
+import process from "process";
+import builtins from "builtin-modules";
+
+const banner =
+`/*
+THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
+if you want to view the source, please visit the github repository of this plugin
+*/
+`;
+
+const prod = (process.argv[2] === "production");
+
+const context = await esbuild.context({
+ banner: {
+ js: banner,
+ },
+ entryPoints: ["main.ts"],
+ bundle: true,
+ external: [
+ "obsidian",
+ "electron",
+ "@codemirror/autocomplete",
+ "@codemirror/collab",
+ "@codemirror/commands",
+ "@codemirror/language",
+ "@codemirror/lint",
+ "@codemirror/search",
+ "@codemirror/state",
+ "@codemirror/view",
+ "@lezer/common",
+ "@lezer/highlight",
+ "@lezer/lr",
+ ...builtins],
+ format: "cjs",
+ target: "es2018",
+ logLevel: "info",
+ sourcemap: prod ? false : "inline",
+ treeShaking: true,
+ outfile: "main.js",
+ minify: prod,
+});
+
+if (prod) {
+ await context.rebuild();
+ process.exit(0);
+} else {
+ await context.watch();
+}
diff --git a/main.ts b/main.ts
new file mode 100644
index 0000000..e7cbd06
--- /dev/null
+++ b/main.ts
@@ -0,0 +1,78 @@
+import { App, Plugin, MarkdownView } from 'obsidian';
+import Calendar from 'src/Calendar';
+import Timeline from 'src/Timeline';
+
+export default class TasksCalendar extends Plugin {
+ app: App;
+
+ async onload() {
+ this.registerMarkdownCodeBlockProcessor("Calendar", (source, el, ctx) => {
+ // Parse the source to extract parameters
+ const lines = source.split('\n');
+ const input: {[name: string]: string} = {};
+ const regex = /^\s*(\w+)\s*:\s*(.*)$/;
+ lines.forEach(line => {
+ const match = line.match(regex);
+ if (match) {
+ const key = match[1].trim();
+ const value = match[2].trim();
+ input[key] = value;
+ }
+ });
+ el.parentElement?.classList.remove('markdown-rendered');
+ // Create a new Calendar instance and call displayCalendar
+ new Calendar(this.app).displayCalendar(input, el.createEl('div'));
+ });
+ this.registerMarkdownCodeBlockProcessor("Taskido", (source, el, ctx) => {
+ // Parse the source to extract parameters
+ const lines = source.split('\n');
+ const input: {[name: string]: string} = {};
+ const regex = /^\s*(\w+)\s*:\s*(.*)$/;
+ lines.forEach(line => {
+ const match = line.match(regex);
+ if (match) {
+ const key = match[1].trim();
+ const value = match[2].trim();
+ input[key] = value;
+ }
+ });
+ el.parentElement?.classList.remove('markdown-rendered');
+ // Create a new Calendar instance and call displayCalendar
+ new Timeline(this.app).createTimeline(input, el.createEl('div'));
+ });
+ this.addCommand({
+ id: 'create-calendar',
+ name: 'Create Calendar',
+ callback: () => {
+ const activeView = this.app.workspace.getActiveViewOfType(MarkdownView);
+ if (activeView) {
+ const editor = activeView.editor;
+ const cursor = editor.getCursor();
+ editor.replaceRange(
+ `\`\`\`Calendar
+ pages: ""
+ view: month
+ firstDayOfWeek: 1
+ options: style1
+ \`\`\``.replaceAll(" ",""), cursor);
+ }
+ }
+ });
+ this.addCommand({
+ id: 'create-timeline',
+ name: 'Create Timeline',
+ callback: () => {
+ const activeView = this.app.workspace.getActiveViewOfType(MarkdownView);
+ if (activeView) {
+ const editor = activeView.editor;
+ const cursor = editor.getCursor();
+ editor.replaceRange(
+ `\`\`\`Taskido
+ pages: ""
+ numberOfDays: 3
+ \`\`\``.replaceAll(" ",""), cursor);
+ }
+ }
+ })
+ }
+}
\ No newline at end of file
diff --git a/manifest.json b/manifest.json
new file mode 100644
index 0000000..d5d131d
--- /dev/null
+++ b/manifest.json
@@ -0,0 +1,11 @@
+{
+ "id": "tasks-calendar",
+ "name": "Tasks Calendar",
+ "version": "2.0.0",
+ "minAppVersion": "0.15.0",
+ "description": "A custom view build with Obsidian-Dataview to display tasks from Obsidian-Tasks and from your daily notes in a highly customisable calendar with a wide variety of views",
+ "author": "702573N",
+ "authorUrl": "https://github.com/702573N",
+ "fundingUrl": "",
+ "isDesktopOnly": false
+}
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..94426c3
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,3029 @@
+{
+ "name": "obsidian-tasks-calendar",
+ "version": "2.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "obsidian-tasks-calendar",
+ "version": "2.0.0",
+ "license": "MIT",
+ "dependencies": {
+ "canvas-confetti": "^1.9.2",
+ "graphology": "^0.25.4",
+ "marked": "^9.1.3",
+ "obsidian-dataview": "^0.5.51",
+ "rrule": "^2.8.1"
+ },
+ "devDependencies": {
+ "@types/canvas-confetti": "^1.6.4",
+ "@types/node": "^16.11.6",
+ "@typescript-eslint/eslint-plugin": "5.29.0",
+ "@typescript-eslint/parser": "5.29.0",
+ "builtin-modules": "3.3.0",
+ "esbuild": "0.17.3",
+ "obsidian": "latest",
+ "sass": "^1.80.6",
+ "tslib": "2.4.0",
+ "typescript": "4.7.4"
+ }
+ },
+ "node_modules/@codemirror/language": {
+ "version": "6.10.3",
+ "resolved": "git+ssh://git@github.com/lishid/cm-language.git#be84c19d93fa87ac4e43c1a5874b1d228b5b2a89",
+ "license": "MIT",
+ "dependencies": {
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.23.0",
+ "@lezer/common": "^1.1.0",
+ "@lezer/highlight": "^1.0.0",
+ "@lezer/lr": "^1.0.0",
+ "style-mod": "^4.0.0"
+ }
+ },
+ "node_modules/@codemirror/state": {
+ "version": "6.4.1",
+ "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.4.1.tgz",
+ "integrity": "sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A==",
+ "license": "MIT"
+ },
+ "node_modules/@codemirror/view": {
+ "version": "6.34.2",
+ "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.34.2.tgz",
+ "integrity": "sha512-d6n0WFvL970A9Z+l9N2dO+Hk9ev4hDYQzIx+B9tCyBP0W5wPEszi1rhuyFesNSkLZzXbQE5FPH7F/z/TMJfoPA==",
+ "license": "MIT",
+ "dependencies": {
+ "@codemirror/state": "^6.4.0",
+ "style-mod": "^4.1.0",
+ "w3c-keyname": "^2.2.4"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.17.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.3.tgz",
+ "integrity": "sha512-1Mlz934GvbgdDmt26rTLmf03cAgLg5HyOgJN+ZGCeP3Q9ynYTNMn2/LQxIl7Uy+o4K6Rfi2OuLsr12JQQR8gNg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.17.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.3.tgz",
+ "integrity": "sha512-XvJsYo3dO3Pi4kpalkyMvfQsjxPWHYjoX4MDiB/FUM4YMfWcXa5l4VCwFWVYI1+92yxqjuqrhNg0CZg3gSouyQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.17.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.3.tgz",
+ "integrity": "sha512-nuV2CmLS07Gqh5/GrZLuqkU9Bm6H6vcCspM+zjp9TdQlxJtIe+qqEXQChmfc7nWdyr/yz3h45Utk1tUn8Cz5+A==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.17.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.3.tgz",
+ "integrity": "sha512-01Hxaaat6m0Xp9AXGM8mjFtqqwDjzlMP0eQq9zll9U85ttVALGCGDuEvra5Feu/NbP5AEP1MaopPwzsTcUq1cw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.17.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.3.tgz",
+ "integrity": "sha512-Eo2gq0Q/er2muf8Z83X21UFoB7EU6/m3GNKvrhACJkjVThd0uA+8RfKpfNhuMCl1bKRfBzKOk6xaYKQZ4lZqvA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.17.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.3.tgz",
+ "integrity": "sha512-CN62ESxaquP61n1ZjQP/jZte8CE09M6kNn3baos2SeUfdVBkWN5n6vGp2iKyb/bm/x4JQzEvJgRHLGd5F5b81w==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.17.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.3.tgz",
+ "integrity": "sha512-feq+K8TxIznZE+zhdVurF3WNJ/Sa35dQNYbaqM/wsCbWdzXr5lyq+AaTUSER2cUR+SXPnd/EY75EPRjf4s1SLg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.17.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.3.tgz",
+ "integrity": "sha512-CLP3EgyNuPcg2cshbwkqYy5bbAgK+VhyfMU7oIYyn+x4Y67xb5C5ylxsNUjRmr8BX+MW3YhVNm6Lq6FKtRTWHQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.17.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.3.tgz",
+ "integrity": "sha512-JHeZXD4auLYBnrKn6JYJ0o5nWJI9PhChA/Nt0G4MvLaMrvXuWnY93R3a7PiXeJQphpL1nYsaMcoV2QtuvRnF/g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.17.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.3.tgz",
+ "integrity": "sha512-FyXlD2ZjZqTFh0sOQxFDiWG1uQUEOLbEh9gKN/7pFxck5Vw0qjWSDqbn6C10GAa1rXJpwsntHcmLqydY9ST9ZA==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.17.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.3.tgz",
+ "integrity": "sha512-OrDGMvDBI2g7s04J8dh8/I7eSO+/E7nMDT2Z5IruBfUO/RiigF1OF6xoH33Dn4W/OwAWSUf1s2nXamb28ZklTA==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.17.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.3.tgz",
+ "integrity": "sha512-DcnUpXnVCJvmv0TzuLwKBC2nsQHle8EIiAJiJ+PipEVC16wHXaPEKP0EqN8WnBe0TPvMITOUlP2aiL5YMld+CQ==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.17.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.3.tgz",
+ "integrity": "sha512-BDYf/l1WVhWE+FHAW3FzZPtVlk9QsrwsxGzABmN4g8bTjmhazsId3h127pliDRRu5674k1Y2RWejbpN46N9ZhQ==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.17.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.3.tgz",
+ "integrity": "sha512-WViAxWYMRIi+prTJTyV1wnqd2mS2cPqJlN85oscVhXdb/ZTFJdrpaqm/uDsZPGKHtbg5TuRX/ymKdOSk41YZow==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.17.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.3.tgz",
+ "integrity": "sha512-Iw8lkNHUC4oGP1O/KhumcVy77u2s6+KUjieUqzEU3XuWJqZ+AY7uVMrrCbAiwWTkpQHkr00BuXH5RpC6Sb/7Ug==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.17.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.3.tgz",
+ "integrity": "sha512-0AGkWQMzeoeAtXQRNB3s4J1/T2XbigM2/Mn2yU1tQSmQRmHIZdkGbVq2A3aDdNslPyhb9/lH0S5GMTZ4xsjBqg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.17.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.3.tgz",
+ "integrity": "sha512-4+rR/WHOxIVh53UIQIICryjdoKdHsFZFD4zLSonJ9RRw7bhKzVyXbnRPsWSfwybYqw9sB7ots/SYyufL1mBpEg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.17.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.3.tgz",
+ "integrity": "sha512-cVpWnkx9IYg99EjGxa5Gc0XmqumtAwK3aoz7O4Dii2vko+qXbkHoujWA68cqXjhh6TsLaQelfDO4MVnyr+ODeA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.17.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.3.tgz",
+ "integrity": "sha512-RxmhKLbTCDAY2xOfrww6ieIZkZF+KBqG7S2Ako2SljKXRFi+0863PspK74QQ7JpmWwncChY25JTJSbVBYGQk2Q==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.17.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.3.tgz",
+ "integrity": "sha512-0r36VeEJ4efwmofxVJRXDjVRP2jTmv877zc+i+Pc7MNsIr38NfsjkQj23AfF7l0WbB+RQ7VUb+LDiqC/KY/M/A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.17.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.3.tgz",
+ "integrity": "sha512-wgO6rc7uGStH22nur4aLFcq7Wh86bE9cOFmfTr/yxN3BXvDEdCSXyKkO+U5JIt53eTOgC47v9k/C1bITWL/Teg==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.17.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.3.tgz",
+ "integrity": "sha512-FdVl64OIuiKjgXBjwZaJLKp0eaEckifbhn10dXWhysMJkWblg3OEEGKSIyhiD5RSgAya8WzP3DNkngtIg3Nt7g==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@eslint-community/eslint-utils": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz",
+ "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "eslint-visitor-keys": "^3.4.3"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
+ }
+ },
+ "node_modules/@eslint-community/regexpp": {
+ "version": "4.12.1",
+ "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz",
+ "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
+ }
+ },
+ "node_modules/@eslint/eslintrc": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz",
+ "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "ajv": "^6.12.4",
+ "debug": "^4.3.2",
+ "espree": "^9.6.0",
+ "globals": "^13.19.0",
+ "ignore": "^5.2.0",
+ "import-fresh": "^3.2.1",
+ "js-yaml": "^4.1.0",
+ "minimatch": "^3.1.2",
+ "strip-json-comments": "^3.1.1"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@eslint/js": {
+ "version": "8.57.1",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz",
+ "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ }
+ },
+ "node_modules/@humanwhocodes/config-array": {
+ "version": "0.13.0",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
+ "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==",
+ "deprecated": "Use @eslint/config-array instead",
+ "dev": true,
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "@humanwhocodes/object-schema": "^2.0.3",
+ "debug": "^4.3.1",
+ "minimatch": "^3.0.5"
+ },
+ "engines": {
+ "node": ">=10.10.0"
+ }
+ },
+ "node_modules/@humanwhocodes/module-importer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
+ "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "peer": true,
+ "engines": {
+ "node": ">=12.22"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/nzakas"
+ }
+ },
+ "node_modules/@humanwhocodes/object-schema": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
+ "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
+ "deprecated": "Use @eslint/object-schema instead",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "peer": true
+ },
+ "node_modules/@lezer/common": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.3.tgz",
+ "integrity": "sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==",
+ "license": "MIT"
+ },
+ "node_modules/@lezer/highlight": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.1.tgz",
+ "integrity": "sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==",
+ "license": "MIT",
+ "dependencies": {
+ "@lezer/common": "^1.0.0"
+ }
+ },
+ "node_modules/@lezer/lr": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.2.tgz",
+ "integrity": "sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==",
+ "license": "MIT",
+ "dependencies": {
+ "@lezer/common": "^1.0.0"
+ }
+ },
+ "node_modules/@nodelib/fs.scandir": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+ "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.stat": "2.0.5",
+ "run-parallel": "^1.1.9"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.stat": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+ "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.walk": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+ "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.scandir": "2.1.5",
+ "fastq": "^1.6.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@parcel/watcher": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.0.tgz",
+ "integrity": "sha512-i0GV1yJnm2n3Yq1qw6QrUrd/LI9bE8WEBOTtOkpCXHHdyN3TAGgqAK/DAT05z4fq2x04cARXt2pDmjWjL92iTQ==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "detect-libc": "^1.0.3",
+ "is-glob": "^4.0.3",
+ "micromatch": "^4.0.5",
+ "node-addon-api": "^7.0.0"
+ },
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ },
+ "optionalDependencies": {
+ "@parcel/watcher-android-arm64": "2.5.0",
+ "@parcel/watcher-darwin-arm64": "2.5.0",
+ "@parcel/watcher-darwin-x64": "2.5.0",
+ "@parcel/watcher-freebsd-x64": "2.5.0",
+ "@parcel/watcher-linux-arm-glibc": "2.5.0",
+ "@parcel/watcher-linux-arm-musl": "2.5.0",
+ "@parcel/watcher-linux-arm64-glibc": "2.5.0",
+ "@parcel/watcher-linux-arm64-musl": "2.5.0",
+ "@parcel/watcher-linux-x64-glibc": "2.5.0",
+ "@parcel/watcher-linux-x64-musl": "2.5.0",
+ "@parcel/watcher-win32-arm64": "2.5.0",
+ "@parcel/watcher-win32-ia32": "2.5.0",
+ "@parcel/watcher-win32-x64": "2.5.0"
+ }
+ },
+ "node_modules/@parcel/watcher-android-arm64": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.0.tgz",
+ "integrity": "sha512-qlX4eS28bUcQCdribHkg/herLe+0A9RyYC+mm2PXpncit8z5b3nSqGVzMNR3CmtAOgRutiZ02eIJJgP/b1iEFQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-darwin-arm64": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.0.tgz",
+ "integrity": "sha512-hyZ3TANnzGfLpRA2s/4U1kbw2ZI4qGxaRJbBH2DCSREFfubMswheh8TeiC1sGZ3z2jUf3s37P0BBlrD3sjVTUw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-darwin-x64": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.0.tgz",
+ "integrity": "sha512-9rhlwd78saKf18fT869/poydQK8YqlU26TMiNg7AIu7eBp9adqbJZqmdFOsbZ5cnLp5XvRo9wcFmNHgHdWaGYA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-freebsd-x64": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.0.tgz",
+ "integrity": "sha512-syvfhZzyM8kErg3VF0xpV8dixJ+RzbUaaGaeb7uDuz0D3FK97/mZ5AJQ3XNnDsXX7KkFNtyQyFrXZzQIcN49Tw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-arm-glibc": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.0.tgz",
+ "integrity": "sha512-0VQY1K35DQET3dVYWpOaPFecqOT9dbuCfzjxoQyif1Wc574t3kOSkKevULddcR9znz1TcklCE7Ht6NIxjvTqLA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-arm-musl": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.0.tgz",
+ "integrity": "sha512-6uHywSIzz8+vi2lAzFeltnYbdHsDm3iIB57d4g5oaB9vKwjb6N6dRIgZMujw4nm5r6v9/BQH0noq6DzHrqr2pA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-arm64-glibc": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.0.tgz",
+ "integrity": "sha512-BfNjXwZKxBy4WibDb/LDCriWSKLz+jJRL3cM/DllnHH5QUyoiUNEp3GmL80ZqxeumoADfCCP19+qiYiC8gUBjA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-arm64-musl": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.0.tgz",
+ "integrity": "sha512-S1qARKOphxfiBEkwLUbHjCY9BWPdWnW9j7f7Hb2jPplu8UZ3nes7zpPOW9bkLbHRvWM0WDTsjdOTUgW0xLBN1Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-x64-glibc": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.0.tgz",
+ "integrity": "sha512-d9AOkusyXARkFD66S6zlGXyzx5RvY+chTP9Jp0ypSTC9d4lzyRs9ovGf/80VCxjKddcUvnsGwCHWuF2EoPgWjw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-x64-musl": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.0.tgz",
+ "integrity": "sha512-iqOC+GoTDoFyk/VYSFHwjHhYrk8bljW6zOhPuhi5t9ulqiYq1togGJB5e3PwYVFFfeVgc6pbz3JdQyDoBszVaA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-win32-arm64": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.0.tgz",
+ "integrity": "sha512-twtft1d+JRNkM5YbmexfcH/N4znDtjgysFaV9zvZmmJezQsKpkfLYJ+JFV3uygugK6AtIM2oADPkB2AdhBrNig==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-win32-ia32": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.0.tgz",
+ "integrity": "sha512-+rgpsNRKwo8A53elqbbHXdOMtY/tAtTzManTWShB5Kk54N8Q9mzNWV7tV+IbGueCbcj826MfWGU3mprWtuf1TA==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-win32-x64": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.0.tgz",
+ "integrity": "sha512-lPrxve92zEHdgeff3aiu4gDOIt4u7sJYha6wbdEZDCDUhtjTsOMiaJzG5lMY4GkWH8p0fMmO2Ppq5G5XXG+DQw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@types/canvas-confetti": {
+ "version": "1.6.4",
+ "resolved": "https://registry.npmjs.org/@types/canvas-confetti/-/canvas-confetti-1.6.4.tgz",
+ "integrity": "sha512-fNyZ/Fdw/Y92X0vv7B+BD6ysHL4xVU5dJcgzgxLdGbn8O3PezZNIJpml44lKM0nsGur+o/6+NZbZeNTt00U1uA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/codemirror": {
+ "version": "5.60.8",
+ "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-5.60.8.tgz",
+ "integrity": "sha512-VjFgDF/eB+Aklcy15TtOTLQeMjTo07k7KAjql8OK5Dirr7a6sJY4T1uVBDuTVG9VEmn1uUsohOpYnVfgC6/jyw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/tern": "*"
+ }
+ },
+ "node_modules/@types/estree": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
+ "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
+ "license": "MIT"
+ },
+ "node_modules/@types/json-schema": {
+ "version": "7.0.15",
+ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
+ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/node": {
+ "version": "16.18.119",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.119.tgz",
+ "integrity": "sha512-ia7V9a2FnhUFfetng4/sRPBMTwHZUkPFY736rb1cg9AgG7MZdR97q7/nLR9om+sq5f1la9C857E0l/nrI0RiFQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/tern": {
+ "version": "0.23.9",
+ "resolved": "https://registry.npmjs.org/@types/tern/-/tern-0.23.9.tgz",
+ "integrity": "sha512-ypzHFE/wBzh+BlH6rrBgS5I/Z7RD21pGhZ2rltb/+ZrVM1awdZwjx7hE5XfuYgHWk9uvV5HLZN3SloevCAp3Bw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "*"
+ }
+ },
+ "node_modules/@typescript-eslint/eslint-plugin": {
+ "version": "5.29.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.29.0.tgz",
+ "integrity": "sha512-kgTsISt9pM53yRFQmLZ4npj99yGl3x3Pl7z4eA66OuTzAGC4bQB5H5fuLwPnqTKU3yyrrg4MIhjF17UYnL4c0w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/scope-manager": "5.29.0",
+ "@typescript-eslint/type-utils": "5.29.0",
+ "@typescript-eslint/utils": "5.29.0",
+ "debug": "^4.3.4",
+ "functional-red-black-tree": "^1.0.1",
+ "ignore": "^5.2.0",
+ "regexpp": "^3.2.0",
+ "semver": "^7.3.7",
+ "tsutils": "^3.21.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "@typescript-eslint/parser": "^5.0.0",
+ "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typescript-eslint/parser": {
+ "version": "5.29.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.29.0.tgz",
+ "integrity": "sha512-ruKWTv+x0OOxbzIw9nW5oWlUopvP/IQDjB5ZqmTglLIoDTctLlAJpAQFpNPJP/ZI7hTT9sARBosEfaKbcFuECw==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "@typescript-eslint/scope-manager": "5.29.0",
+ "@typescript-eslint/types": "5.29.0",
+ "@typescript-eslint/typescript-estree": "5.29.0",
+ "debug": "^4.3.4"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typescript-eslint/scope-manager": {
+ "version": "5.29.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.29.0.tgz",
+ "integrity": "sha512-etbXUT0FygFi2ihcxDZjz21LtC+Eps9V2xVx09zFoN44RRHPrkMflidGMI+2dUs821zR1tDS6Oc9IXxIjOUZwA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/types": "5.29.0",
+ "@typescript-eslint/visitor-keys": "5.29.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/type-utils": {
+ "version": "5.29.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.29.0.tgz",
+ "integrity": "sha512-JK6bAaaiJozbox3K220VRfCzLa9n0ib/J+FHIwnaV3Enw/TO267qe0pM1b1QrrEuy6xun374XEAsRlA86JJnyg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/utils": "5.29.0",
+ "debug": "^4.3.4",
+ "tsutils": "^3.21.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "*"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typescript-eslint/types": {
+ "version": "5.29.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.29.0.tgz",
+ "integrity": "sha512-X99VbqvAXOMdVyfFmksMy3u8p8yoRGITgU1joBJPzeYa0rhdf5ok9S56/itRoUSh99fiDoMtarSIJXo7H/SnOg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree": {
+ "version": "5.29.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.29.0.tgz",
+ "integrity": "sha512-mQvSUJ/JjGBdvo+1LwC+GY2XmSYjK1nAaVw2emp/E61wEVYEyibRHCqm1I1vEKbXCpUKuW4G7u9ZCaZhJbLoNQ==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "@typescript-eslint/types": "5.29.0",
+ "@typescript-eslint/visitor-keys": "5.29.0",
+ "debug": "^4.3.4",
+ "globby": "^11.1.0",
+ "is-glob": "^4.0.3",
+ "semver": "^7.3.7",
+ "tsutils": "^3.21.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typescript-eslint/utils": {
+ "version": "5.29.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.29.0.tgz",
+ "integrity": "sha512-3Eos6uP1nyLOBayc/VUdKZikV90HahXE5Dx9L5YlSd/7ylQPXhLk1BYb29SDgnBnTp+jmSZUU0QxUiyHgW4p7A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/json-schema": "^7.0.9",
+ "@typescript-eslint/scope-manager": "5.29.0",
+ "@typescript-eslint/types": "5.29.0",
+ "@typescript-eslint/typescript-estree": "5.29.0",
+ "eslint-scope": "^5.1.1",
+ "eslint-utils": "^3.0.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ }
+ },
+ "node_modules/@typescript-eslint/visitor-keys": {
+ "version": "5.29.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.29.0.tgz",
+ "integrity": "sha512-Hpb/mCWsjILvikMQoZIE3voc9wtQcS0A9FUw3h8bhr9UxBdtI/tw1ZDZUOXHXLOVMedKCH5NxyzATwnU78bWCQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/types": "5.29.0",
+ "eslint-visitor-keys": "^3.3.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@ungap/structured-clone": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
+ "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==",
+ "dev": true,
+ "license": "ISC",
+ "peer": true
+ },
+ "node_modules/acorn": {
+ "version": "8.14.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
+ "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-jsx": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+ "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "peerDependencies": {
+ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ }
+ },
+ "node_modules/ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true,
+ "license": "Python-2.0",
+ "peer": true
+ },
+ "node_modules/array-union": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
+ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fill-range": "^7.1.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/builtin-modules": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz",
+ "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/canvas-confetti": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/canvas-confetti/-/canvas-confetti-1.9.3.tgz",
+ "integrity": "sha512-rFfTURMvmVEX1gyXFgn5QMn81bYk70qa0HLzcIOSVEyl57n6o9ItHeBtUSWdvKAPY0xlvBHno4/v3QPrT83q9g==",
+ "license": "ISC",
+ "funding": {
+ "type": "donate",
+ "url": "https://www.paypal.me/kirilvatev"
+ }
+ },
+ "node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/chokidar": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz",
+ "integrity": "sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "readdirp": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 14.16.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/cross-spawn": {
+ "version": "7.0.5",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.5.tgz",
+ "integrity": "sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/debug": {
+ "version": "4.3.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
+ "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/deep-is": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
+ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/detect-libc": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
+ "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "bin": {
+ "detect-libc": "bin/detect-libc.js"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/dir-glob": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
+ "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "path-type": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/doctrine": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+ "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "esutils": "^2.0.2"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/emoji-regex": {
+ "version": "10.4.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz",
+ "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==",
+ "license": "MIT"
+ },
+ "node_modules/esbuild": {
+ "version": "0.17.3",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.3.tgz",
+ "integrity": "sha512-9n3AsBRe6sIyOc6kmoXg2ypCLgf3eZSraWFRpnkto+svt8cZNuKTkb1bhQcitBcvIqjNiK7K0J3KPmwGSfkA8g==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "optionalDependencies": {
+ "@esbuild/android-arm": "0.17.3",
+ "@esbuild/android-arm64": "0.17.3",
+ "@esbuild/android-x64": "0.17.3",
+ "@esbuild/darwin-arm64": "0.17.3",
+ "@esbuild/darwin-x64": "0.17.3",
+ "@esbuild/freebsd-arm64": "0.17.3",
+ "@esbuild/freebsd-x64": "0.17.3",
+ "@esbuild/linux-arm": "0.17.3",
+ "@esbuild/linux-arm64": "0.17.3",
+ "@esbuild/linux-ia32": "0.17.3",
+ "@esbuild/linux-loong64": "0.17.3",
+ "@esbuild/linux-mips64el": "0.17.3",
+ "@esbuild/linux-ppc64": "0.17.3",
+ "@esbuild/linux-riscv64": "0.17.3",
+ "@esbuild/linux-s390x": "0.17.3",
+ "@esbuild/linux-x64": "0.17.3",
+ "@esbuild/netbsd-x64": "0.17.3",
+ "@esbuild/openbsd-x64": "0.17.3",
+ "@esbuild/sunos-x64": "0.17.3",
+ "@esbuild/win32-arm64": "0.17.3",
+ "@esbuild/win32-ia32": "0.17.3",
+ "@esbuild/win32-x64": "0.17.3"
+ }
+ },
+ "node_modules/escape-string-regexp": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/eslint": {
+ "version": "8.57.1",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz",
+ "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
+ "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.2.0",
+ "@eslint-community/regexpp": "^4.6.1",
+ "@eslint/eslintrc": "^2.1.4",
+ "@eslint/js": "8.57.1",
+ "@humanwhocodes/config-array": "^0.13.0",
+ "@humanwhocodes/module-importer": "^1.0.1",
+ "@nodelib/fs.walk": "^1.2.8",
+ "@ungap/structured-clone": "^1.2.0",
+ "ajv": "^6.12.4",
+ "chalk": "^4.0.0",
+ "cross-spawn": "^7.0.2",
+ "debug": "^4.3.2",
+ "doctrine": "^3.0.0",
+ "escape-string-regexp": "^4.0.0",
+ "eslint-scope": "^7.2.2",
+ "eslint-visitor-keys": "^3.4.3",
+ "espree": "^9.6.1",
+ "esquery": "^1.4.2",
+ "esutils": "^2.0.2",
+ "fast-deep-equal": "^3.1.3",
+ "file-entry-cache": "^6.0.1",
+ "find-up": "^5.0.0",
+ "glob-parent": "^6.0.2",
+ "globals": "^13.19.0",
+ "graphemer": "^1.4.0",
+ "ignore": "^5.2.0",
+ "imurmurhash": "^0.1.4",
+ "is-glob": "^4.0.0",
+ "is-path-inside": "^3.0.3",
+ "js-yaml": "^4.1.0",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "levn": "^0.4.1",
+ "lodash.merge": "^4.6.2",
+ "minimatch": "^3.1.2",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.9.3",
+ "strip-ansi": "^6.0.1",
+ "text-table": "^0.2.0"
+ },
+ "bin": {
+ "eslint": "bin/eslint.js"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint-scope": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
+ "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^4.1.1"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/eslint-utils": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz",
+ "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "eslint-visitor-keys": "^2.0.0"
+ },
+ "engines": {
+ "node": "^10.0.0 || ^12.0.0 || >= 14.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/mysticatea"
+ },
+ "peerDependencies": {
+ "eslint": ">=5"
+ }
+ },
+ "node_modules/eslint-utils/node_modules/eslint-visitor-keys": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
+ "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/eslint-visitor-keys": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+ "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint/node_modules/eslint-scope": {
+ "version": "7.2.2",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
+ "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "peer": true,
+ "dependencies": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint/node_modules/estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "peer": true,
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/espree": {
+ "version": "9.6.1",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
+ "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "peer": true,
+ "dependencies": {
+ "acorn": "^8.9.0",
+ "acorn-jsx": "^5.3.2",
+ "eslint-visitor-keys": "^3.4.1"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/esquery": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz",
+ "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "peer": true,
+ "dependencies": {
+ "estraverse": "^5.1.0"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/esquery/node_modules/estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "peer": true,
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/esrecurse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+ "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/esrecurse/node_modules/estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/estraverse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
+ "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/esutils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "peer": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/events": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
+ "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8.x"
+ }
+ },
+ "node_modules/fast-deep-equal": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/fast-glob": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
+ "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.2",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.4"
+ },
+ "engines": {
+ "node": ">=8.6.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/fast-json-stable-stringify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/fast-levenshtein": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/fastq": {
+ "version": "1.17.1",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
+ "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "reusify": "^1.0.4"
+ }
+ },
+ "node_modules/file-entry-cache": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
+ "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "flat-cache": "^3.0.4"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/find-up": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/flat-cache": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz",
+ "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "flatted": "^3.2.9",
+ "keyv": "^4.5.3",
+ "rimraf": "^3.0.2"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ }
+ },
+ "node_modules/flatted": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz",
+ "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==",
+ "dev": true,
+ "license": "ISC",
+ "peer": true
+ },
+ "node_modules/fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+ "dev": true,
+ "license": "ISC",
+ "peer": true
+ },
+ "node_modules/functional-red-black-tree": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
+ "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "deprecated": "Glob versions prior to v9 are no longer supported",
+ "dev": true,
+ "license": "ISC",
+ "peer": true,
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+ "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+ "dev": true,
+ "license": "ISC",
+ "peer": true,
+ "dependencies": {
+ "is-glob": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/globals": {
+ "version": "13.24.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
+ "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "type-fest": "^0.20.2"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/globby": {
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
+ "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "array-union": "^2.1.0",
+ "dir-glob": "^3.0.1",
+ "fast-glob": "^3.2.9",
+ "ignore": "^5.2.0",
+ "merge2": "^1.4.1",
+ "slash": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/graphemer": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
+ "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/graphology": {
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/graphology/-/graphology-0.25.4.tgz",
+ "integrity": "sha512-33g0Ol9nkWdD6ulw687viS8YJQBxqG5LWII6FI6nul0pq6iM2t5EKquOTFDbyTblRB3O9I+7KX4xI8u5ffekAQ==",
+ "license": "MIT",
+ "dependencies": {
+ "events": "^3.3.0",
+ "obliterator": "^2.0.2"
+ },
+ "peerDependencies": {
+ "graphology-types": ">=0.24.0"
+ }
+ },
+ "node_modules/graphology-types": {
+ "version": "0.24.7",
+ "resolved": "https://registry.npmjs.org/graphology-types/-/graphology-types-0.24.7.tgz",
+ "integrity": "sha512-tdcqOOpwArNjEr0gNQKCXwaNCWnQJrog14nJNQPeemcLnXQUUGrsCWpWkVKt46zLjcS6/KGoayeJfHHyPDlvwA==",
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ignore": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
+ "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/immediate": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
+ "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==",
+ "license": "MIT"
+ },
+ "node_modules/immutable": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.0.2.tgz",
+ "integrity": "sha512-1NU7hWZDkV7hJ4PJ9dur9gTNQ4ePNPN4k9/0YhwjzykTi/+3Q5pF93YU5QoVj8BuOnhLgaY8gs0U2pj4kSYVcw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/import-fresh": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+ "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=0.8.19"
+ }
+ },
+ "node_modules/inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+ "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
+ "dev": true,
+ "license": "ISC",
+ "peer": true,
+ "dependencies": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true,
+ "license": "ISC",
+ "peer": true
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/is-path-inside": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
+ "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+ "dev": true,
+ "license": "ISC",
+ "peer": true
+ },
+ "node_modules/js-yaml": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+ "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "argparse": "^2.0.1"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/json-buffer": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
+ "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/json-stable-stringify-without-jsonify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/keyv": {
+ "version": "4.5.4",
+ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
+ "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "json-buffer": "3.0.1"
+ }
+ },
+ "node_modules/levn": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+ "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "prelude-ls": "^1.2.1",
+ "type-check": "~0.4.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/lie": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz",
+ "integrity": "sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==",
+ "license": "MIT",
+ "dependencies": {
+ "immediate": "~3.0.5"
+ }
+ },
+ "node_modules/localforage": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/localforage/-/localforage-1.10.0.tgz",
+ "integrity": "sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "lie": "3.1.1"
+ }
+ },
+ "node_modules/locate-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "p-locate": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/lodash.merge": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/luxon": {
+ "version": "3.5.0",
+ "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.5.0.tgz",
+ "integrity": "sha512-rh+Zjr6DNfUYR3bPwJEnuwDdqMbxZW7LOQfUN4B54+Cl+0o5zaU9RJ6bcidfDtC1cWCZXQ+nvX8bf6bAji37QQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/marked": {
+ "version": "9.1.6",
+ "resolved": "https://registry.npmjs.org/marked/-/marked-9.1.6.tgz",
+ "integrity": "sha512-jcByLnIFkd5gSXZmjNvS1TlmRhCXZjIzHYlaGkPlLIekG55JDR2Z4va9tZwCiP+/RDERiNhMOFu01xd6O5ct1Q==",
+ "license": "MIT",
+ "bin": {
+ "marked": "bin/marked.js"
+ },
+ "engines": {
+ "node": ">= 16"
+ }
+ },
+ "node_modules/merge2": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/micromatch": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+ "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "braces": "^3.0.3",
+ "picomatch": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "license": "ISC",
+ "peer": true,
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/moment": {
+ "version": "2.29.4",
+ "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
+ "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==",
+ "license": "MIT",
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/natural-compare": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/node-addon-api": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz",
+ "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/obliterator": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.4.tgz",
+ "integrity": "sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==",
+ "license": "MIT"
+ },
+ "node_modules/obsidian": {
+ "version": "1.7.2",
+ "resolved": "https://registry.npmjs.org/obsidian/-/obsidian-1.7.2.tgz",
+ "integrity": "sha512-k9hN9brdknJC+afKr5FQzDRuEFGDKbDjfCazJwpgibwCAoZNYHYV8p/s3mM8I6AsnKrPKNXf8xGuMZ4enWelZQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/codemirror": "5.60.8",
+ "moment": "2.29.4"
+ },
+ "peerDependencies": {
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.0.0"
+ }
+ },
+ "node_modules/obsidian-calendar-ui": {
+ "version": "0.3.12",
+ "resolved": "https://registry.npmjs.org/obsidian-calendar-ui/-/obsidian-calendar-ui-0.3.12.tgz",
+ "integrity": "sha512-hdoRqCPnukfRgCARgArXaqMQZ+Iai0eY7f0ZsFHHfywpv4gKg3Tx5p47UsLvRO5DD+4knlbrL7Gel57MkfcLTw==",
+ "license": "MIT",
+ "dependencies": {
+ "obsidian-daily-notes-interface": "0.8.4",
+ "svelte": "3.35.0",
+ "tslib": "2.1.0"
+ }
+ },
+ "node_modules/obsidian-calendar-ui/node_modules/tslib": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz",
+ "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==",
+ "license": "0BSD"
+ },
+ "node_modules/obsidian-daily-notes-interface": {
+ "version": "0.8.4",
+ "resolved": "https://registry.npmjs.org/obsidian-daily-notes-interface/-/obsidian-daily-notes-interface-0.8.4.tgz",
+ "integrity": "sha512-REKQtAuIOKDbvNH/th1C1gWmJWCP5tRn9T/mfZGZt4Zncgko7McXK0aSKFtEInipvgbZJ2nScivvyLdiWluSMw==",
+ "license": "MIT",
+ "dependencies": {
+ "obsidian": "github:obsidianmd/obsidian-api#master",
+ "tslib": "2.1.0"
+ },
+ "bin": {
+ "obsidian-daily-notes-interface": "dist/main.js"
+ }
+ },
+ "node_modules/obsidian-daily-notes-interface/node_modules/obsidian": {
+ "version": "1.7.2",
+ "resolved": "git+ssh://git@github.com/obsidianmd/obsidian-api.git#23947b58d372ea02225324308e31d36b4aa95869",
+ "license": "MIT",
+ "dependencies": {
+ "@types/codemirror": "5.60.8",
+ "moment": "2.29.4"
+ },
+ "peerDependencies": {
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.0.0"
+ }
+ },
+ "node_modules/obsidian-daily-notes-interface/node_modules/tslib": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz",
+ "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==",
+ "license": "0BSD"
+ },
+ "node_modules/obsidian-dataview": {
+ "version": "0.5.67",
+ "resolved": "https://registry.npmjs.org/obsidian-dataview/-/obsidian-dataview-0.5.67.tgz",
+ "integrity": "sha512-nLQrjvZ6Ny5s6mCfi+rv0TsdYkKTV4YfDqyLNixxNkyLCqgE9AXKJlJNnkv3Ic1brGOw2m/0SgtdWykKzobwMQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@codemirror/language": "git+https://github.com/lishid/cm-language.git",
+ "@codemirror/state": "^6.0.1",
+ "@codemirror/view": "^6.0.1",
+ "emoji-regex": "^10.0.0",
+ "localforage": "^1.10.0",
+ "luxon": "^3.2.0",
+ "obsidian-calendar-ui": "^0.3.12",
+ "papaparse": "^5.3.1",
+ "parsimmon": "^1.18.0",
+ "preact": "^10.6.5"
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "dev": true,
+ "license": "ISC",
+ "peer": true,
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/optionator": {
+ "version": "0.9.4",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
+ "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "deep-is": "^0.1.3",
+ "fast-levenshtein": "^2.0.6",
+ "levn": "^0.4.1",
+ "prelude-ls": "^1.2.1",
+ "type-check": "^0.4.0",
+ "word-wrap": "^1.2.5"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/p-limit": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "yocto-queue": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-locate": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "p-limit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/papaparse": {
+ "version": "5.4.1",
+ "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.4.1.tgz",
+ "integrity": "sha512-HipMsgJkZu8br23pW15uvo6sib6wne/4woLZPlFf3rpDyMe9ywEXUsuD7+6K9PRkJlVT51j/sCOYDKGGS3ZJrw==",
+ "license": "MIT"
+ },
+ "node_modules/parent-module": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+ "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "callsites": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/parsimmon": {
+ "version": "1.18.1",
+ "resolved": "https://registry.npmjs.org/parsimmon/-/parsimmon-1.18.1.tgz",
+ "integrity": "sha512-u7p959wLfGAhJpSDJVYXoyMCXWYwHia78HhRBWqk7AIbxdmlrfdp5wX0l3xv/iTSH5HvhN9K7o26hwwpgS5Nmw==",
+ "license": "MIT"
+ },
+ "node_modules/path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-type": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/preact": {
+ "version": "10.24.3",
+ "resolved": "https://registry.npmjs.org/preact/-/preact-10.24.3.tgz",
+ "integrity": "sha512-Z2dPnBnMUfyQfSQ+GBdsGa16hz35YmLmtTLhM169uW944hYL6xzTYkJjC07j+Wosz733pMWx0fgON3JNw1jJQA==",
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/preact"
+ }
+ },
+ "node_modules/prelude-ls": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/punycode": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
+ "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/queue-microtask": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/readdirp": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz",
+ "integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 14.16.0"
+ },
+ "funding": {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/regexpp": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
+ "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/mysticatea"
+ }
+ },
+ "node_modules/resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/reusify": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "iojs": ">=1.0.0",
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rimraf": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+ "deprecated": "Rimraf versions prior to v4 are no longer supported",
+ "dev": true,
+ "license": "ISC",
+ "peer": true,
+ "dependencies": {
+ "glob": "^7.1.3"
+ },
+ "bin": {
+ "rimraf": "bin.js"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/rrule": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/rrule/-/rrule-2.8.1.tgz",
+ "integrity": "sha512-hM3dHSBMeaJ0Ktp7W38BJZ7O1zOgaFEsn41PDk+yHoEtfLV+PoJt9E9xAlZiWgf/iqEqionN0ebHFZIDAp+iGw==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/run-parallel": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+ "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "queue-microtask": "^1.2.2"
+ }
+ },
+ "node_modules/sass": {
+ "version": "1.80.7",
+ "resolved": "https://registry.npmjs.org/sass/-/sass-1.80.7.tgz",
+ "integrity": "sha512-MVWvN0u5meytrSjsU7AWsbhoXi1sc58zADXFllfZzbsBT1GHjjar6JwBINYPRrkx/zqnQ6uqbQuHgE95O+C+eQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "chokidar": "^4.0.0",
+ "immutable": "^5.0.2",
+ "source-map-js": ">=0.6.2 <2.0.0"
+ },
+ "bin": {
+ "sass": "sass.js"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "optionalDependencies": {
+ "@parcel/watcher": "^2.4.1"
+ }
+ },
+ "node_modules/semver": {
+ "version": "7.6.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
+ "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "shebang-regex": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/slash": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/source-map-js": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-json-comments": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/style-mod": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz",
+ "integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==",
+ "license": "MIT"
+ },
+ "node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/svelte": {
+ "version": "3.35.0",
+ "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.35.0.tgz",
+ "integrity": "sha512-gknlZkR2sXheu/X+B7dDImwANVvK1R0QGQLd8CNIfxxGPeXBmePnxfzb6fWwTQRsYQG7lYkZXvpXJvxvpsoB7g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/text-table": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/tslib": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
+ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==",
+ "license": "0BSD"
+ },
+ "node_modules/tsutils": {
+ "version": "3.21.0",
+ "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
+ "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^1.8.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ },
+ "peerDependencies": {
+ "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta"
+ }
+ },
+ "node_modules/tsutils/node_modules/tslib": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+ "dev": true,
+ "license": "0BSD"
+ },
+ "node_modules/type-check": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+ "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "prelude-ls": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/type-fest": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+ "dev": true,
+ "license": "(MIT OR CC0-1.0)",
+ "peer": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "4.7.4",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz",
+ "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=4.2.0"
+ }
+ },
+ "node_modules/uri-js": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+ "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "peer": true,
+ "dependencies": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "node_modules/w3c-keyname": {
+ "version": "2.2.8",
+ "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
+ "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==",
+ "license": "MIT"
+ },
+ "node_modules/which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
+ "license": "ISC",
+ "peer": true,
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/word-wrap": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
+ "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "dev": true,
+ "license": "ISC",
+ "peer": true
+ },
+ "node_modules/yocto-queue": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..66d5917
--- /dev/null
+++ b/package.json
@@ -0,0 +1,33 @@
+{
+ "name": "obsidian-tasks-calendar",
+ "version": "2.0.0",
+ "description": "A custom view build with Obsidian-Dataview to display tasks from Obsidian-Tasks and from your daily notes in a highly customisable calendar with a wide variety of views",
+ "main": "main.js",
+ "scripts": {
+ "dev": "node esbuild.config.mjs",
+ "build": "sass src/scss/style.scss styles.css && tsc --noEmit --skipLibCheck && node esbuild.config.mjs production",
+ "version": "node version-bump.mjs && git add manifest.json versions.json"
+ },
+ "keywords": [],
+ "author": "702573N",
+ "license": "MIT",
+ "devDependencies": {
+ "@types/canvas-confetti": "^1.6.4",
+ "@types/node": "^16.11.6",
+ "@typescript-eslint/eslint-plugin": "5.29.0",
+ "@typescript-eslint/parser": "5.29.0",
+ "builtin-modules": "3.3.0",
+ "esbuild": "0.17.3",
+ "obsidian": "latest",
+ "sass": "^1.80.6",
+ "tslib": "2.4.0",
+ "typescript": "4.7.4"
+ },
+ "dependencies": {
+ "canvas-confetti": "^1.9.2",
+ "graphology": "^0.25.4",
+ "marked": "^9.1.3",
+ "obsidian-dataview": "^0.5.51",
+ "rrule": "^2.8.1"
+ }
+}
diff --git a/src/Calendar.ts b/src/Calendar.ts
new file mode 100644
index 0000000..9879220
--- /dev/null
+++ b/src/Calendar.ts
@@ -0,0 +1,480 @@
+import { App, moment } from 'obsidian';
+import { getAPI } from 'obsidian-dataview';
+import { arrowLeftIcon, arrowRightIcon, filterIcon, monthIcon, weekIcon, listIcon } from './Tools/Calendar';
+import { cellTemplate, taskNumberTemplate } from './Tools/Calendar';
+import { getCurrent, getMeta, getTasks, setTaskContentContainer, updateCounters } from './Tools/Calendar';
+import { setStatisticPopUp, setWeekViewContext, setStatisticValues, removeExistingView } from './Tools/Calendar';
+
+export default class Calendar {
+ dv: any;
+ tasks: any;
+ rootNode: HTMLElement;
+ firstDayOfWeek: number;
+ upcomingDays: number;
+ dailyNoteFolder: string;
+ taskCountOnly: boolean;
+ selectedDate: any;
+ constructor(app: App){
+ this.dv = getAPI(app);
+ }
+ checkForErrors = (input: {[name: string]: string}, el: HTMLElement) => {
+ let {view, firstDayOfWeek, dailyNoteFormat, startPosition, options} = input;
+ if (!options.includes("style")) {
+ el.createSpan('> [!ERROR] Missing style parameter\n> \n> Please set a style inside options parameter like\n> \n> `options: "style1"`')
+ return false;
+ }
+ if (!view) {
+ el.createSpan('> [!ERROR] Missing view parameter\n> \n> Please set a default view inside view parameter like\n> \n> `view: "month"`');
+ return false;
+ }
+ if (firstDayOfWeek) {
+ if (firstDayOfWeek.match(/[|\\0123456]/g) == null) {
+ el.createSpan('> [!ERROR] Wrong value inside firstDayOfWeek parameter\n> \n> Please choose a number between 0 and 6');
+ return false;
+ };
+ } else {
+ el.createSpan('> [!ERROR] Missing firstDayOfWeek parameter\n> \n> Please set the first day of the week inside firstDayOfWeek parameter like\n> \n> `firstDayOfWeek: "1"`');
+ return false;
+ };
+ if (startPosition && !startPosition.match(/\d{4}\-\d{1,2}/gm)) {
+ el.createSpan('> [!ERROR] Wrong startPosition format\n> \n> Please set a startPosition with the following format\n> \n> Month: `YYYY-MM` | Week: `YYYY-ww`');
+ return false;
+ }
+ if (dailyNoteFormat && dailyNoteFormat.match(/[|\\YMDWwd.,-: \[\]]/g) && dailyNoteFormat.match(/[|\\YMDWwd.,-: \[\]]/g)!.length != dailyNoteFormat.length) {
+ el.createSpan('> [!ERROR] The `dailyNoteFormat` contains invalid characters');
+ return false;
+ }
+ return true;
+ }
+
+ setTasks = (pages: string, hideFileWithProps: string) => {
+ let dvPages;
+ if (pages == "") {
+ dvPages = this.dv.pages();
+ } else if (typeof pages === "string" && pages.startsWith("dv.pages")) {
+ const pagesContent = pages.match(/\((.*)\)/)?.[1];
+ if (pagesContent) {
+ dvPages = this.dv.pages(pagesContent);
+ } else {
+ dvPages = this.dv.pages();
+ }
+ } else {
+ dvPages = this.dv.pages(pages);
+ }
+ if (hideFileWithProps) {
+ this.tasks = dvPages.flatMap((p: any) => {
+ let tasks = p.file.tasks;
+ hideFileWithProps.split(",").forEach((prop: string) => {
+ if(p[prop.trim()])
+ tasks = tasks.filter((task: any) => task.checked);
+ });
+ return tasks;
+ });
+ }else{
+ this.tasks = dvPages.file.tasks;
+ }
+ }
+ displayCalendar = (input: {[name: string]: string}, element: HTMLElement) => {
+ if(!this.checkForErrors(input, element)){
+ return false;
+ }
+ let {pages, view, firstDayOfWeek, globalTaskFilter, dailyNoteFolder, dailyNoteFormat, startPosition, upcomingDays,
+ css, options, taskCountOnly, disableRecurrence, hideFileWithProps} = input;
+ this.firstDayOfWeek = firstDayOfWeek? parseInt(firstDayOfWeek) : 0;
+ this.upcomingDays = upcomingDays? parseInt(upcomingDays) : 7;
+ this.dailyNoteFolder = dailyNoteFolder ? dailyNoteFolder : "";
+ this.taskCountOnly = taskCountOnly == "true";
+ this.setTasks(pages, hideFileWithProps);
+ // Variables
+ let tid = (new Date()).getTime();
+ if (view.toLowerCase() == "month") {
+ this.selectedDate = moment(startPosition || moment(), "YYYY-MM").date(1);
+ } else if (view.toLowerCase() == "week") {
+ this.selectedDate = moment(startPosition || moment(), "YYYY-ww").startOf("week");
+ } else if (view.toLowerCase() == "list") {
+ this.selectedDate = moment(startPosition || moment(), "YYYY-MM").date(1);
+ }
+ this.rootNode = element as HTMLElement;
+ this.rootNode.classList.add("tasksCalendar");
+ options.split(" ").forEach((option: string) => {
+ this.rootNode.classList.add(option);
+ });
+ this.rootNode.setAttribute("id", "tasksCalendar"+tid);
+ this.rootNode.setAttribute("view", view);
+ this.rootNode.setAttribute("style", 'position:relative;-webkit-user-select:none!important');
+ this.rootNode.createSpan();
+ if (css) {
+ let style = document.createElement("style");
+ style.innerHTML = css;
+ this.rootNode.append(style)
+ }
+ // Initialze
+ getMeta(dailyNoteFormat, globalTaskFilter, disableRecurrence == "true", this.tasks);
+ this.setButtons();
+ setStatisticPopUp(this.rootNode);
+ setWeekViewContext(this.rootNode);
+ if(view.toLowerCase() == "month") {
+ this.getMonth();
+ } else if(view.toLowerCase() == "week") {
+ this.getWeek();
+ } else if(view.toLowerCase() == "list") {
+ this.getList();
+ }
+ }
+
+ setButtonEvents = () => {
+ this.rootNode.querySelectorAll('button').forEach(btn => btn.addEventListener('click', (() => {
+ let activeView = this.rootNode.getAttribute("view");
+ if ( btn.className == "previous" ) {
+ if (activeView == "month") {
+ this.selectedDate = moment(this.selectedDate).subtract(1, "months");
+ this.getMonth();
+ } else if (activeView == "week") {
+ this.selectedDate = moment(this.selectedDate).subtract(7, "days").startOf("week");
+ this.getWeek();
+ } else if (activeView == "list") {
+ this.selectedDate = moment(this.selectedDate).subtract(1, "months");
+ this.getList();
+ }
+ } else if ( btn.className == "current") {
+ if (activeView == "month") {
+ this.selectedDate = moment().date(1);
+ this.getMonth();
+ } else if (activeView == "week") {
+ this.selectedDate = moment().startOf("week");
+ this.getWeek();
+ } else if (activeView == "list") {
+ this.selectedDate = moment().date(1);
+ this.getList();
+ };
+ } else if ( btn.className == "next" ) {
+ if (activeView == "month") {
+ this.selectedDate = moment(this.selectedDate).add(1, "months");
+ this.getMonth();
+ } else if (activeView == "week") {
+ this.selectedDate = moment(this.selectedDate).add(7, "days").startOf("week");
+ this.getWeek();
+ } else if (activeView == "list") {
+ this.selectedDate = moment(this.selectedDate).add(1, "months");
+ this.getList();
+ };
+ } else if ( btn.className == "filter" ) {
+ this.rootNode.classList.toggle("filter");
+ this.rootNode.querySelector('#statisticDone')!.classList.remove("active");
+ this.rootNode.classList.remove("focusDone");
+ } else if ( btn.className == "monthView" ) {
+ if ( moment().format("ww-YYYY") == moment(this.selectedDate).format("ww-YYYY") ) {
+ this.selectedDate = moment().date(1);
+ } else {
+ this.selectedDate = moment(this.selectedDate).date(1);
+ };
+ this.getMonth();
+ } else if ( btn.className == "listView" ) {
+ if ( moment().format("ww-YYYY") == moment(this.selectedDate).format("ww-YYYY") ) {
+ this.selectedDate = moment().date(1);
+ } else {
+ this.selectedDate = moment(this.selectedDate).date(1);
+ };
+ this.getList();
+ } else if ( btn.className == "weekView" ) {
+ if (this.rootNode.getAttribute("view") == "week") {
+ let leftPos = (this.rootNode.querySelector("button.weekView") as HTMLElement).offsetLeft;
+ (this.rootNode.querySelector(".weekViewContext") as HTMLElement).style.left = leftPos+"px";
+ this.rootNode.querySelector(".weekViewContext")!.classList.toggle("active");
+ if (this.rootNode.querySelector(".weekViewContext")!.classList.contains("active")) {
+ let closeContextListener = function() {
+ this.rootNode.querySelector(".weekViewContext").classList.remove("active");
+ this.rootNode.removeEventListener("click", closeContextListener, false);
+ };
+ setTimeout(function() {
+ this.rootNode.addEventListener("click", closeContextListener, false);
+ }, 100);
+ };
+ } else {
+ if (moment().format("MM-YYYY") != moment(this.selectedDate).format("MM-YYYY")) {
+ this.selectedDate = moment(this.selectedDate).startOf("month").startOf("week");
+ } else {
+ this.selectedDate = moment().startOf("week");
+ };
+ this.getWeek();
+ };
+ } else if ( btn.className == "statistic" ) {
+ this.rootNode.querySelector(".statisticPopup")!.classList.toggle("active");
+ };
+ btn.blur();
+ })));
+ this.rootNode.addEventListener('contextmenu', function(event) {
+ event.preventDefault();
+ });
+ }
+ setButtons = () => {
+ let buttons = `
+
+ ${filterIcon}
+
+
+ ${listIcon}
+
+
+ ${monthIcon}
+
+
+ ${weekIcon}
+
+
+
+
+ ${arrowLeftIcon}
+
+
+ ${arrowRightIcon}
+
+
+ `;
+ let buttonsEl = this.rootNode.createEl("div", {cls: "buttons"});
+ buttonsEl.innerHTML = buttons;
+ this.rootNode.querySelector("span")!.appendChild(buttonsEl);
+ this.setButtonEvents();
+ };
+ getMonth = async () => {
+ removeExistingView(this.rootNode);
+ this.rootNode.querySelector('button.current')!.innerHTML = `${moment(this.selectedDate).format("MMMM")} ${moment(this.selectedDate).format("YYYY")} `;
+ let firstDayOfMonth = parseInt(moment(this.selectedDate).format("d"));
+ let lastDateOfMonth = parseInt(moment(this.selectedDate).endOf("month").format("D"));
+ let counter = {
+ due: 0,
+ done: 0,
+ overdue: 0,
+ start: 0,
+ scheduled: 0,
+ recurrence: 0,
+ dailyNote: 0
+ }
+ let monthName = moment(this.selectedDate).format("MMM").replace(".","").substring(0,3);
+ let current = getCurrent();
+
+ // Move First Week Of Month To Second Week In Month View
+ if (firstDayOfMonth == 0)
+ firstDayOfMonth = 7;
+
+ // Set Grid Heads
+ let gridHeads = "";
+ for (let h=0-firstDayOfMonth+this.firstDayOfWeek;h<7-firstDayOfMonth+this.firstDayOfWeek;h++) {
+ let weekDayNr = moment(this.selectedDate).add(h, "days").format("d");
+ let weekDayName = moment(this.selectedDate).add(h, "days").format("ddd");
+ if ( current.day == weekDayNr && current.month == moment(this.selectedDate).format("M") && current.year == moment(this.selectedDate).format("YYYY") ) {
+ gridHeads += `${weekDayName}
`;
+ } else {
+ gridHeads += `${weekDayName}
`;
+ };
+ };
+
+
+ const tasksPromises = [];
+ // Set Wrappers
+ let wrappers = "";
+ let starts = 0-firstDayOfMonth+this.firstDayOfWeek;
+ for (let w=1; w<7; w++) {
+ tasksPromises.push((async () => {
+ let wrapper = "";
+ let weekNr = "";
+ let yearNr = "";
+ for (let i=starts;i= 0 && i < lastDateOfMonth && current.today !== currentDate) {
+ cls = "currentMonth";
+ } else if ( i >= 0 && i< lastDateOfMonth && current.today == currentDate) {
+ cls = "currentMonth today";
+ } else if (i >= lastDateOfMonth) {
+ cls = "nextMonth";
+ }
+ // Set Cell Name And Weekday
+ if(this.taskCountOnly){
+ cellContent = taskNumberTemplate(status.length, cls);
+ }
+ if ( parseInt(moment(this.selectedDate).add(i, "days").format("D")) == 1 ) {
+ wrapper += cellTemplate(`${cls} newMonth`, weekDay, dailyNotePath, longDayName, cellContent);
+ } else {
+ wrapper += cellTemplate(cls, weekDay, dailyNotePath, shortDayName, cellContent);
+ }
+ }
+ wrappers += ``;
+ starts += 7;
+ })());
+ };
+ let gridEl = this.rootNode.createEl("div", {cls: "grid"});
+ gridEl.innerHTML = `
+ ${wrappers}
`;
+ this.rootNode.querySelector("span")!.appendChild(gridEl);
+ this.setWrapperEvents();
+ setStatisticValues(this.rootNode, counter);
+ this.rootNode.setAttribute("view", "month");
+ }
+ getWeek = async () => {
+ removeExistingView(this.rootNode);
+ if (this.rootNode.querySelector('button.current'))
+ this.rootNode.querySelector('button.current')!.innerHTML = `${moment(this.selectedDate).format("YYYY")} ${moment(this.selectedDate).format("[W]w")} `;
+
+ let gridContent = "";
+ let currentWeekday = parseInt(moment(this.selectedDate).format("d"));
+ let weekNr = moment(this.selectedDate).format("[W]w");
+ let counter = {
+ due: 0,
+ done: 0,
+ overdue: 0,
+ start: 0,
+ scheduled: 0,
+ recurrence: 0,
+ dailyNote: 0
+ }
+ let current = getCurrent();
+
+ const tasksPromises = [];
+
+ for (let i = 0 - currentWeekday + this.firstDayOfWeek; i < 7 - currentWeekday + this.firstDayOfWeek; i++) {
+ tasksPromises.push((async () => {
+ let currentDate = moment(this.selectedDate).add(i, "days").format("YYYY-MM-DD");
+ let dailyNotePath = this.dailyNoteFolder + "/" + currentDate;
+ let weekDay = moment(this.selectedDate).add(i, "days").format("d");
+ let dayName = moment(currentDate).format("ddd D.");
+ let longDayName = moment(currentDate).format("ddd, D. MMM");
+
+ // Filter Tasks
+ let status = await getTasks(this.tasks, currentDate);
+
+ // Count Events From Selected Week
+ updateCounters(status, counter, currentDate);
+
+ // Set New Content Container
+ let cellContent;
+
+ // Set Cell Name And Weekday
+ let cell;
+ let cls = "";
+ // Set Today, Before Today, After Today
+ if (currentDate < current.today) {
+ cls = "beforeToday";
+ } else if (currentDate == current.today) {
+ cls = "today";
+ } else if (currentDate > current.today) {
+ cls = "afterToday";
+ };
+ // Set Cell Name And Weekday
+ if (this.taskCountOnly) {
+ cellContent = taskNumberTemplate(status.length, cls);
+ } else {
+ cellContent = setTaskContentContainer(status, this.dv, currentDate);
+ }
+ if (parseInt(moment(this.selectedDate).add(i, "days").format("D")) == 1) {
+ cell = cellTemplate(cls, weekDay, dailyNotePath, longDayName, cellContent);
+ } else {
+ cell = cellTemplate(cls, weekDay, dailyNotePath, dayName, cellContent);
+ };
+
+ gridContent += cell;
+ })());
+ }
+
+ await Promise.all(tasksPromises);
+
+ let gridEl = this.rootNode.createEl("div", { cls: "grid", attr: { "data-week": weekNr } });
+ gridEl.innerHTML = gridContent;
+ this.rootNode.querySelector("span")!.appendChild(gridEl);
+ setStatisticValues(this.rootNode, counter);
+ this.rootNode.setAttribute("view", "week");
+ }
+
+ getList = async () => {
+ removeExistingView(this.rootNode);
+ this.rootNode.querySelector('button.current')!.innerHTML = `${moment(this.selectedDate).format("MMMM")} ${moment(this.selectedDate).format("YYYY")} `;
+ let listContent = "";
+ let counter = {
+ due: 0,
+ done: 0,
+ overdue: 0,
+ start: 0,
+ scheduled: 0,
+ recurrence: 0,
+ dailyNote: 0
+ }
+ let monthName = moment(this.selectedDate).format("MMM").replace(".","").substring(0,3);
+
+ const tasksPromises = [];
+ // Loop Days From Current Month
+ for (let i=0;i{
+ let currentDate = moment(this.selectedDate).startOf('month').add(i, "days").format("YYYY-MM-DD");
+
+ // Filter Tasks
+ let status = getTasks(this.tasks, currentDate);
+
+ // Count Events
+ updateCounters(status, counter, currentDate);
+ if (moment().format("YYYY-MM-DD") == currentDate) {
+ let overdueDetails = `Overdue ${setTaskContentContainer(status.filter((t: any)=> t.type == "overdue"), this.dv, currentDate)} `;
+ let todayDetails = `Today ${setTaskContentContainer(status.filter((t: any)=> t.type != "overdue"), this.dv, currentDate)} `;
+
+ // Upcoming
+ let upcomingContent = "";
+ for (let t=1;tUpcoming ${upcomingContent}`;
+
+ listContent += `${moment(currentDate).format("dddd, D")} ${moment(currentDate).format("[W]w")} ${overdueDetails}${todayDetails}${upcomingDetails}
`
+
+ } else {
+ listContent += `${moment(currentDate).format("dddd, D")} ${moment(currentDate).format("[W]w")} ${setTaskContentContainer(status, this.dv, currentDate)}
`
+ }
+ })());
+ }
+ await Promise.all(tasksPromises);
+ let listContentEl = this.rootNode.createEl("div", {cls: "grid list"});
+ listContentEl.innerHTML = listContent;
+ listContentEl.setAttribute("data-month", monthName);
+ this.rootNode.querySelector("span")!.appendChild(listContentEl);
+ setStatisticValues(this.rootNode, counter);
+ this.rootNode.setAttribute("view", "list");
+
+ // Scroll To Today If Selected Month Is Current Month
+ if ( moment().format("YYYY-MM") == moment(this.selectedDate).format("YYYY-MM") ) {
+ let listElement = this.rootNode.querySelector(".list")!;
+ let todayElement = this.rootNode.querySelector(".today")! as HTMLElement;
+ let scrollPos = todayElement.offsetTop - todayElement.offsetHeight + 85;
+ listElement.scrollTo(0, scrollPos);
+ }
+ }
+ setWrapperEvents = () => {
+ this.rootNode.querySelectorAll('.wrapperButton').forEach(wBtn => wBtn.addEventListener('click', (() => {
+ let week = parseInt(wBtn.getAttribute("data-week")!);
+ let year = wBtn.getAttribute("data-year");
+ this.selectedDate = moment(moment(year).add(week - 1, "weeks")).startOf("week");
+ this.rootNode.querySelector(`.grid`)!.remove();
+ this.getWeek();
+ })));
+ };
+}
\ No newline at end of file
diff --git a/src/Timeline.ts b/src/Timeline.ts
new file mode 100644
index 0000000..e773ca3
--- /dev/null
+++ b/src/Timeline.ts
@@ -0,0 +1,385 @@
+import { App, moment, TFile, Notice, MarkdownView } from 'obsidian';
+import { getAPI } from 'obsidian-dataview';
+import { Icons } from './Tools/Timeline';
+import { getMeta, getRelative, getSelectOptions, addNewTask } from './Tools/Timeline';
+import { getMetaFromNote, getFilename, IsRecurringThisDay, sortTasks } from './Tools/Utils';
+import { DurationInputArg1, DurationInputArg2 } from 'moment';
+
+export default class Timeline {
+ app: App;
+ dv: any;
+ rootNode: HTMLElement;
+ tasks: any;
+ taskFiles: Array;
+ section: string;
+ timelineDates: Array;
+ constructor(app: App) {
+ this.app = app;
+ this.dv = getAPI(app);
+ }
+ checkErrors = (input: {[name: string]: string}) =>{
+ let {pages, dailyNoteFormat} = input;
+ // Error Handling
+ if (!pages && pages!="") { this.rootNode.createSpan('> [!ERROR] Missing pages parameter\n> \n> Please set the pages parameter like\n> \n> `pages: ""`'); return true };
+ if (dailyNoteFormat) { if (dailyNoteFormat.match(/[|\\YMDWwd.,-: \[\]]/g)?.length != dailyNoteFormat.length) { this.rootNode.createSpan('> [!ERROR] The `dailyNoteFormat` contains invalid characters'); return true }};
+ }
+ setTasks = (pages: string, hideFileWithProps: string) => {
+ let dvPages;
+ if (pages == "") {
+ dvPages = this.dv.pages();
+ } else if (typeof pages === "string" && pages.startsWith("dv.pages")) {
+ const pagesContent = pages.match(/\((.*)\)/)?.[1];
+ if (pagesContent) {
+ dvPages = this.dv.pages(pagesContent);
+ } else {
+ dvPages = this.dv.pages();
+ }
+ } else {
+ dvPages = this.dv.pages(pages);
+ }
+ if (hideFileWithProps) {
+ this.tasks = dvPages.flatMap((p: any) => {
+ let tasks = p.file.tasks;
+ hideFileWithProps.split(",").forEach((prop: string) => {
+ if(p[prop.trim()])
+ tasks = tasks.filter((task: any) => task.checked);
+ });
+ return tasks;
+ });
+ }else{
+ this.tasks = dvPages.file.tasks;
+ }
+ }
+
+ createTimeline = (input: {[name: string]: string}, el: HTMLElement) => {
+ let {pages, inbox, select, taskFiles, dailyNoteFolder, dailyNoteFormat, css, dateFormat, options, section, hideFileWithProps} = input;
+ // Set Root
+ let tid = (new Date()).getTime();
+ this.section = section;
+ this.rootNode = el.createEl("div", {cls: "taskido "+options || "", attr: {id: "taskido"+tid}});
+ this.rootNode.createSpan();
+ if(this.checkErrors(input)) return;
+ this.setTasks(pages, hideFileWithProps);
+ // Get, Set, Eval Pages
+ if (!taskFiles) {
+ this.taskFiles = [...new Set(this.dv.pages().file.map((f: any)=>f.tasks.filter((t: any)=>!t.completed)).path)].sort();
+ } else {
+ this.taskFiles = [...new Set(this.dv.pagePaths(taskFiles))].sort()
+ }
+ if (dailyNoteFolder && !dailyNoteFolder.endsWith("/")) {
+ dailyNoteFolder = dailyNoteFolder+"/";
+ }
+ if (!dateFormat) {
+ dateFormat = "ddd, MMM D";
+ }
+ if (!select) {
+ select = "dailyNote";
+ }
+
+ if (css) {
+ let style = this.rootNode.createEl("style");
+ style.innerHTML = css;
+ this.rootNode.querySelector("span")!.append(style);
+ }
+
+ // Initialze
+ this.timelineDates = getMeta(this.tasks, input);
+ this.getTimeline(dateFormat);
+ getSelectOptions(this.rootNode, dailyNoteFolder || "", dailyNoteFormat, this.taskFiles, inbox, select);
+ this.setEvents();
+ }
+ setEvents = () => {
+ this.rootNode.querySelectorAll('.counter').forEach(cnt => cnt.addEventListener('click', (() => {
+ let activeFocus = Array.from(this.rootNode.classList).filter(c=>c.endsWith("Filter") && !c.startsWith("today"))[0];
+ if (activeFocus == cnt.id+"Filter") {
+ this.rootNode.classList.remove(activeFocus);
+ return false;
+ };
+ this.rootNode.classList.remove.apply(this.rootNode.classList, Array.from(this.rootNode.classList).filter(c=>c.endsWith("Filter") && !c.startsWith("today")));
+ this.rootNode.classList.add(cnt.id+"Filter");
+ })));
+ this.rootNode.querySelector('.todayHeader')?.addEventListener('click', (() => {
+ this.rootNode.classList.toggle("todayFocus");
+ }));
+ this.rootNode.querySelectorAll('.task:not(.star, .add)').forEach(t => t.addEventListener('click', ((e: MouseEvent) => {
+ let link = t.getAttribute("data-link") || "";
+ let line = t.getAttribute("data-line") || "";
+ let col = t.getAttribute("data-col") || "";
+ if ((e.target as Element)?.closest(".task .tag")) {
+ // Tag
+ } else if ((e.target as Element)?.closest(".timeline .icon")) {
+ // Check
+ let task = (e.target as Element)?.closest(".task");
+ let icon = (e.target as Element)?.closest(".timeline .icon");
+ if(task) task.className = "task done";
+ if(icon) icon.innerHTML = Icons.done;
+ this.completeTask(link, line, col);
+ } else {
+ // File
+ this.openFile(link, line, col);
+ };
+ })));
+ this.rootNode.querySelector('.ok')?.addEventListener('click', (() => {
+ let filePath = (this.rootNode.querySelector('.fileSelect') as HTMLSelectElement)?.value;
+ let newTask = (this.rootNode.querySelector('.newTask') as HTMLInputElement)?.value;
+ if (newTask.length > 1) {
+ try {
+ let abstractFilePath = this.app.vault.getAbstractFileByPath(filePath);
+ if (abstractFilePath && abstractFilePath instanceof TFile) {
+ this.app.vault.process(abstractFilePath, (fileText: string) => addNewTask(fileText, newTask, this.section));
+ } else {
+ this.app.vault.create(filePath, "- [ ] " + newTask);
+ };
+ new Notice("New task saved!");
+ if(this.rootNode.querySelector('.newTask') != null){
+ (this.rootNode.querySelector('.newTask') as HTMLInputElement).value = "";
+ (this.rootNode.querySelector('.newTask') as HTMLInputElement).focus();
+ }
+ } catch(err) {
+ new Notice("Something went wrong!");
+ };
+ } else {
+ (this.rootNode.querySelector('.newTask') as HTMLInputElement).focus();
+ };
+ }));
+ this.rootNode.querySelector('.fileSelect')?.addEventListener('change', (() => {
+ (this.rootNode.querySelector('.newTask') as HTMLInputElement).focus();
+ }));
+ (this.rootNode.querySelector('.newTask') as HTMLInputElement).addEventListener('input', (() => {
+ let input = (this.rootNode.querySelector('.newTask') as HTMLInputElement);
+ let newTask = input.value;
+
+ // Icons
+ if (newTask.includes("due ")) { input.value = newTask.replace("due", "📅") };
+ if (newTask.includes("start ")) { input.value = newTask.replace("start", "🛫") };
+ if (newTask.includes("scheduled ")) { input.value = newTask.replace("scheduled", "⏳") };
+ if (newTask.includes("done ")) { input.value = newTask.replace("done", "✅") };
+ if (newTask.includes("high ")) { input.value = newTask.replace("high", "⏫") };
+ if (newTask.includes("medium ")) { input.value = newTask.replace("medium", "🔼") };
+ if (newTask.includes("low ")) { input.value = newTask.replace("low", "🔽") };
+ if (newTask.includes("repeat ")) { input.value = newTask.replace("repeat", "🔁") };
+ if (newTask.includes("recurring ")) { input.value = newTask.replace("recurring", "🔁") };
+
+ // Dates
+ if (newTask.includes("today ")) { input.value = newTask.replace("today", moment().format("YYYY-MM-DD")) };
+ if (newTask.includes("tomorrow ")) { input.value = newTask.replace("tomorrow", moment().add(1, "days").format("YYYY-MM-DD")) };
+ if (newTask.includes("yesterday ")) { input.value = newTask.replace("yesterday", moment().subtract(1, "days").format("YYYY-MM-DD")) };
+
+ // In X days/weeks/month/years
+ let futureDate = newTask.match(/(in)\W(\d{1,3})\W(days|day|weeks|week|month|years|year) /);
+ if (futureDate) {
+ let x = parseInt(futureDate[2]);
+ let unit = futureDate[3];
+ let date = moment().add(x as DurationInputArg1, unit as DurationInputArg2).format("YYYY-MM-DD[ ]")
+ input.value = newTask.replace(futureDate[0], date);
+ };
+
+ // Next Weekday
+ let weekday = newTask.match(/(monday|tuesday|wednesday|thursday|friday|saturday|sunday) /);
+ if (weekday) {
+ let weekdays = ["","monday","tuesday","wednesday","thursday","friday","saturday","sunday"];
+ const dayINeed = weekdays.indexOf(weekday[1]);
+ if (moment().isoWeekday() < dayINeed) {
+ input.value = newTask.replace(weekday[1], moment().isoWeekday(dayINeed).format("YYYY-MM-DD"));
+ } else {
+ input.value = newTask.replace(weekday[1], moment().add(1, 'weeks').isoWeekday(dayINeed).format("YYYY-MM-DD"));
+ }
+ }
+
+ (this.rootNode.querySelector('.newTask') as HTMLInputElement).focus();
+ }));
+ this.rootNode.querySelector('.newTask')?.addEventListener('keyup', ((e: KeyboardEvent) => {
+ if (e.key === "Enter") { // Enter key
+ (this.rootNode.querySelector('.ok') as HTMLElement)?.click();
+ };
+ }));
+ this.rootNode.querySelector('.newTask')?.addEventListener('focus', (() => {
+ this.rootNode.querySelector('.quickEntryPanel')?.classList.add("focus");
+ }));
+ this.rootNode.querySelector('.newTask')?.addEventListener('blur', (() => {
+ this.rootNode.querySelector('.quickEntryPanel')?.classList.remove("focus");
+ }));
+ };
+
+ openFile = (link: string, line: string, col: string) =>{
+ this.app.workspace.openLinkText('', link).then(() => {
+ if (line && col) {
+ try {
+ const view = this.app.workspace.getMostRecentLeaf()!.getViewState();
+ view.state!.mode = 'source'; // mode = source || preview
+ this.app.workspace.getMostRecentLeaf()!.setViewState(view);
+ let cmEditor = this.app.workspace.getActiveViewOfType(MarkdownView)!.editor;
+ cmEditor.setSelection({line: parseInt(line), ch: 6},{line: parseInt(line), ch: parseInt(col)});
+ cmEditor.focus();
+ } catch(err) {
+ new Notice("Something went wrong!")
+ }
+ }
+ })
+ }
+
+ completeTask = (link: string, line: string, col: string) => {
+ this.app.workspace.openLinkText('', link).then(() => {
+ if (line && col) {
+ try {
+ const view = this.app.workspace.getMostRecentLeaf()!.getViewState();
+ view.state!.mode = 'source'; // mode = source || preview
+ this.app.workspace.getMostRecentLeaf()!.setViewState(view);
+ let cmEditor = this.app.workspace.getActiveViewOfType(MarkdownView)!.editor;
+ let cmLine = cmEditor.getLine(parseInt(line));
+ let addRange;
+ if (cmLine.includes("🔁")) {
+ addRange = 1
+ } else {
+ addRange = 0
+ }
+ cmEditor.setCursor(parseInt(line), parseInt(col));
+ //@ts-ignore
+ this.app.commands.executeCommandById('obsidian-tasks-plugin:toggle-done');
+ cmEditor.setSelection({line: parseInt(line) + addRange, ch: 6},{line: parseInt(line) + addRange, ch: parseInt(col) + 13});
+ cmEditor.focus();
+ } catch(err) {
+ new Notice("Something went wrong!")
+ }
+ }
+ });
+ }
+
+ getTimeline = (dateFormat: string) => {
+ let yearNode;
+ let lastYear = null;
+ let containedTypesPerYear = null;
+ for (let timelineDate of this.timelineDates) {
+ // Variables
+ let tasksFiltered = this.tasks.filter((t: any)=>(Object.values(t.happens).includes(timelineDate.toString())) ||
+ (IsRecurringThisDay(t, timelineDate)) && !t.done).sort((t:any)=>t, "asc", sortTasks);
+ let date = moment(timelineDate.toString()).format(dateFormat);
+ let weekday = moment(timelineDate.toString()).format("dddd");
+ let year = moment(timelineDate.toString()).format("YYYY");
+ let today = moment().format("YYYY-MM-DD");
+ let detailsCls = "";
+ let content = "";
+ let containedTypesPerDay: Array = [];
+
+ // Add Year Section
+ if (year != lastYear) {
+ containedTypesPerYear = [];
+ lastYear = year;
+ yearNode = this.rootNode.createEl("div", {cls: "year", attr: {"data-types": ""}});
+ if (moment().format("YYYY") == year) { yearNode.classList.add("current") };
+ yearNode.innerHTML = year;
+ this.rootNode.querySelector("span")!.appendChild(yearNode);
+ };
+
+ // Add Today Information
+ if (timelineDate == today) {
+ detailsCls += "today";
+
+ let overdueCount = this.tasks.filter((t: any)=>t.happens["overdue"]).length;
+ // let dueCount = tasksFiltered.filter((t: any)=>t.happens["due"]).length;
+ // let startCount = tasksFiltered.filter((t: any)=>t.happens["start"]).length;
+ // let scheduledCount = tasksFiltered.filter((t: any)=>t.happens["scheduled"]).length;
+ // let doneCount = tasksFiltered.filter((t: any)=>t.happens["done"]).length;
+ // let dailynoteCount = tasksFiltered.filter((t: any)=>t.happens["dailynote"]).length;
+ // let processCount = tasksFiltered.filter((t: any)=>t.happens["process"]).length;
+ let todoCount = tasksFiltered.filter((t: any)=>!t.completed && !t.happens["overdue"] && !t.happens["unplanned"]).length;
+ let unplannedCount = this.tasks.filter((t: any)=>t.happens["unplanned"]).length;
+ // let allCount = doneCount + todoCount + overdueCount;
+
+ // Counter
+ content = `
+
+
+
+
${overdueCount}
+
Overdue
+
+
+
${unplannedCount}
+
Unplanned
+
+
+ `;
+ }
+
+ tasksFiltered.forEach((item: any) => {
+ let file = getFilename(item.path);
+ let header = item.header.subpath || item.path.replace(/.*\/([^\/]+)\.[^\.]+$/, '$1');
+ let link = item.link.path.replace("'", "'");
+ let text = item.text;
+ let posEndLine = item.position.start.line;
+ let posEndCol = item.position.end.col;
+ let info = "";
+ let color = getMetaFromNote(item, "color", this.dv);
+ if (!color) {color = "var(--text-muted)"};
+ let cls = Object.keys(item.happens).find(key => item.happens[key] === timelineDate.toString())?.replace("Forward","") || "";
+ if(cls == "" && item.recurrence) {cls = "repeat"};
+ let dailyNote = item.dailyNote;
+ containedTypesPerDay.push(cls);
+ containedTypesPerYear.push(cls);
+ // Handle forwarded tasks to get relative by cls
+ for(let key in item.happens) {
+ let value = item.happens[key];
+ let relative = getRelative(value as string);
+ // Append relative infos
+ if (!key.includes("Forward") && key != "unplanned") {
+ info += `${Icons[key as keyof typeof Icons]}
${relative}
`;
+ }
+ }
+
+ if (item.repeat) {
+ info += `${Icons.repeat}
${item.repeat.replace("🔁", "")}
`;
+ };
+
+ if (item.priorityLabel) {
+ info += `${Icons.priority}
${item.priorityLabel}
`;
+ };
+
+ info += ``;
+
+ item.tags.forEach(function(tag: string) {
+ let tagText = tag.replace("#","");
+ let hexColorMatch = tag.match(/([a-fA-F0-9]{6}|[a-fA-F0-9]{3})\/(.*)/);
+ let style;
+ if (hexColorMatch) {
+ style = "style='--tag-color:#" + hexColorMatch[1] + ";--tag-background:#" + hexColorMatch[1] + "1a'";
+ tagText = hexColorMatch[2];
+ } else {
+ style = "style='--tag-color:var(--text-muted)'";
+ };
+ info += "" + Icons.tag + "
" + tagText + "
";
+ text = text.replace(tag, "");
+ });
+ let icon;
+ if (item.completed) { icon = Icons.done } else { icon = Icons.task };
+ if (cls == "overdue") { icon = Icons.alert } else if (cls == "cancelled") { icon = Icons.cancelled };
+ let task = "";
+ content += task;
+ });
+
+ // Set Date Template
+ let dateTemplate = "" + content + "
"
+
+ // Append To Root Node
+ containedTypesPerDay = [...new Set(containedTypesPerDay)].sort();
+ let element = this.rootNode.createEl("div", {cls: `details ${detailsCls}`, attr: {"data-year": year, "data-types": containedTypesPerDay.join(" ")}});
+ element.innerHTML = dateTemplate;
+ this.rootNode.querySelector("span")!.appendChild(element);
+
+ // Set containedTypesPerYear
+ containedTypesPerYear = [...new Set(containedTypesPerYear)].sort() as Array;
+ yearNode?.setAttribute("data-types", containedTypesPerYear.join(" "));
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/Tools/Calendar.ts b/src/Tools/Calendar.ts
new file mode 100644
index 0000000..4a687a6
--- /dev/null
+++ b/src/Tools/Calendar.ts
@@ -0,0 +1,384 @@
+import { moment } from "obsidian";
+import { isNotCompletedOrCancelled, isTimePassed, hasTimeFormat, getTime} from './Utils'
+import { getFilename, momentToRegex, getMetaFromNote, IsRecurringThisDay, isDueOrScheduled, isTime, sortTasks } from './Utils';
+
+/**
+ * List of icons
+ */
+const arrowLeftIcon = ' ';
+const arrowRightIcon = ' ';
+const filterIcon = ' ';
+const monthIcon = ' ';
+const weekIcon = ' ';
+const listIcon = ' ';
+const calendarClockIcon = ' ';
+const calendarCheckIcon = ' ';
+const calendarHeartIcon = ' ';
+
+export { arrowLeftIcon, arrowRightIcon, filterIcon, monthIcon, weekIcon, listIcon };
+
+/**
+ * List of templates
+ */
+const cellTemplate = (cls: string, weekday: string, dailyNote: string, cellName: string, cellContent: string) =>
+ ``;
+const taskTemplate = (taskPath: string, cls: string, style: string, title: string, note: string, icon: string, relative: string, taskContent: string) =>
+ `${note}
${icon}
${taskContent}
`;
+const taskNumberTemplate = (number: number, cls: string) => `${number}
`;
+
+export { cellTemplate, taskNumberTemplate };
+
+
+const capitalize = (str: string): string =>
+ str[0].toUpperCase() + str.slice(1);
+
+const getCurrent = () => ({
+ today: moment().format("YYYY-MM-DD"),
+ day: moment().format("d"),
+ month: moment().format("M"),
+ year: moment().format("YYYY")
+});
+
+const getMeta = (dailyNoteFormat : string, globalTaskFilter: string, disableRecurrence: boolean, tasks: any) =>{
+ if (!dailyNoteFormat)
+ dailyNoteFormat = "YYYY-MM-DD";
+ if(!globalTaskFilter)
+ globalTaskFilter = "#task";
+ let dailyNoteRegEx = momentToRegex(dailyNoteFormat);
+ for (let task of tasks) {
+ let taskText = task.text;
+ let taskFile = getFilename(task.path);
+ let dueMatch = taskText.match(/\📅\W(\d{4}\-\d{2}\-\d{2})/);
+ let scheduledMatch = taskText.match(/\⏳\W(\d{4}\-\d{2}\-\d{2})/);
+ let startMatch = taskText.match(/\🛫\W(\d{4}\-\d{2}\-\d{2})/);
+ let completionMatch = taskText.match(/\✅\W(\d{4}\-\d{2}\-\d{2})/);
+ let cancelledMatch = taskText.match(/\❌\W(\d{4}\-\d{2}\-\d{2})/);
+ let dailyNoteMatch = taskFile?.match(dailyNoteRegEx);
+ let dailyTaskMatch = taskText.match(/(\d{4}\-\d{2}\-\d{2})/);
+ let repeatMatch = taskText.includes("🔁");
+ let matchResult = taskText.match(/🔁\s*(.*?)\s*[🛫⏳📅⌚]/);
+ if (dueMatch) {
+ task.due = dueMatch[1];
+ task.text = task.text.replace(dueMatch[0], "");
+ };
+ if (scheduledMatch) {
+ task.scheduled = scheduledMatch[1];
+ task.text = task.text.replace(scheduledMatch[0], "");
+ };
+ if (startMatch) {
+ task.start = startMatch[1];
+ task.text = task.text.replace(startMatch[0], "");
+ };
+ if (completionMatch) {
+ task.completion = completionMatch[1];
+ task.text = task.text.replace(completionMatch[0], "");
+ }
+ if(cancelledMatch){
+ task.cancelled = cancelledMatch[1];
+ task.text = task.text.replace(cancelledMatch[0], "");
+ }
+ if(isOverdue(task)){
+ task.type = "overdue";
+ task.typePriority = 1;
+ task.moment = task.due ? moment(task.due) : moment(task.scheduled);
+ }else if(isTimePassed(task)){
+ task.type = "timePassed";
+ task.typePriority = 2;
+ let time = getTime(taskText).split(":");
+ let day = task.due ? moment(task.due) : moment(task.scheduled);
+ task.moment = day.add(parseInt(time[0]), "hours").add(parseInt(time[1]), "minutes");
+ }else if(isDueOrScheduled(task) && !hasTimeFormat(task)){
+ if((task.due && task.scheduled && moment(task.due).isSameOrBefore(task.scheduled)) || task.due){
+ task.type = "due";
+ task.typePriority = 3;
+ task.moment = moment(task.due);
+ }else if(task.scheduled){
+ task.type = "scheduled";
+ task.typePriority = 3;
+ task.moment = moment(task.scheduled);
+ }
+ }else if(isStart(task)){
+ task.type = "start";
+ task.typePriority = 4;
+ task.moment = moment(task.start);
+ }else if(isTime(task)){
+ task.type = "time";
+ task.typePriority = 5;
+ let time = getTime(taskText).split(":");
+ let day = task.due ? moment(task.due) : moment(task.scheduled);
+ task.moment = day.add(parseInt(time[0]), "hours").add(parseInt(time[1]), "minutes");
+ }else if(isDone(task)){
+ task.type = "done";
+ task.typePriority = 6;
+ task.moment = moment(task.completion);
+ }else if(isCancelled(task)){
+ task.type = "cancelled";
+ task.typePriority = 7;
+ if(task.cancelled)
+ task.moment = moment(task.cancelled);
+ }
+ if (dailyNoteMatch && !dailyTaskMatch) {
+ task.dailyNote = moment(dailyNoteMatch[1], dailyNoteFormat).format("YYYY-MM-DD");
+ }
+ if (task.type != "done" && task.type != "cancelled" && repeatMatch) {
+ task.recurrence = true;
+ if(!disableRecurrence){
+ task.recurringValue = matchResult ? matchResult[1] : "";
+ }
+ task.text = task.text.substring(0, taskText.indexOf("🔁"))
+ };
+
+ if(taskText.includes("🔺")){
+ task.priority = 0;
+ }else if (taskText.includes("⏫")) {
+ task.priority = 1;
+ }else if (taskText.includes("🔼")) {
+ task.priority = 2;
+ }else if (taskText.includes("🔽")) {
+ task.priority = 3;
+ }else {
+ task.priority = 4;
+ }
+ task.text = task.text.replaceAll(globalTaskFilter,"").replaceAll("[[","").replaceAll("]]","").replace(/\[.*?\]/gm,"");
+ }
+}
+
+const getTasks = (tasks : any, date: any) =>
+ tasks.filter((t: any) => filterTasks(t, date)).sort((t:any)=>t, "asc", sortTasks);
+
+const isOverdue = (task: any) =>
+ isNotCompletedOrCancelled(task) && (
+ (task.due && moment(task.due).isBefore(moment(), 'day'))
+ ||(task.scheduled && moment(task.scheduled).isBefore(moment(), 'day')));
+
+
+
+const isStart = (task: any) =>
+ isNotCompletedOrCancelled(task) && task.start;
+
+
+const isDone = (task: any) =>
+ task.completed && task.checked;
+
+const isCancelled = (task: any) =>
+ !task.completed && task.checked;
+
+const setTaskContentContainer = (status: any,dv: any, date: any, skipRecurrences?: boolean) => {
+ let cellContent = "";
+ for (let task of status) {
+ if(skipRecurrences && task.recurrence) continue;
+ let type = task.recurrence && !(task.moment && task.moment.isSame(date, 'day')) ? "recurrence" : task.type;
+ cellContent += setTask(task, type, dv)
+ };
+ return cellContent;
+}
+
+const updateCounters = (status: any, counter: {[key: string]: number}, currentDate: any) => {
+ for(let key in counter)
+ if(key != "overdue")
+ counter[key] += status.filter((t:any)=>t.type == key).length;
+ counter.recurrence += status.filter((t:any)=>t.recurrence && !(t.type == "overdue" && moment().isSame(currentDate, 'day'))).length;
+ counter.overdue += status.filter((t:any)=>t.type == "overdue" && moment().isSame(currentDate, 'day')).length;
+}
+
+export { getCurrent, getMeta, getTasks, setTaskContentContainer, updateCounters};
+const setStatisticPopUp = (rootNode: HTMLElement) => {
+ let element = rootNode.createEl("ul", {cls: "statisticPopup"});
+ element.innerHTML = `
+
+
+
+
+
+
+
+
+
+ `;
+ rootNode.querySelector("span")!.appendChild(element);
+ setStatisticPopUpEvents(rootNode);
+};
+
+const setWeekViewContext = (rootNode: HTMLElement) =>{
+ let activeStyle = Array.from(rootNode.classList).filter(v=>v.startsWith("style"))[0];
+ let liElements = "";
+ for (let i=1;i<12;i++) {
+ liElements += `
+
+ Style ${i}
+ `;
+ };
+ let element = rootNode.createEl("ul", {cls: "weekViewContext"});
+ element.innerHTML = liElements;
+ rootNode.querySelector("span")!.appendChild(element);
+ setWeekViewContextEvents(rootNode);
+};
+
+const setStatisticValues = (rootNode: HTMLElement, counter: {[key: string]: number}) =>{
+ const { due, done, overdue, start, scheduled, recurrence, dailyNote } = counter;
+ let taskCounter = due+done+overdue;
+ let tasksRemaining = (taskCounter - done) as string | number;
+ let percentage = Math.round(100/(due+done+overdue)*done);
+ percentage = isNaN(percentage) ? 100 : percentage;
+ if(rootNode.querySelector("button.statistic")){
+ if (due == 0 && done == 0) {
+ rootNode.querySelector("button.statistic")!.innerHTML = calendarHeartIcon;
+ } else if (tasksRemaining as number > 0) {
+ rootNode.querySelector("button.statistic")!.innerHTML = calendarClockIcon;
+ } else if (due == 0 && done != 0) {
+ rootNode.querySelector("button.statistic")!.innerHTML = calendarCheckIcon;
+ }
+ }
+ if (tasksRemaining as number > 99) {tasksRemaining = "⚠️"};
+ if(rootNode.querySelector("button.statistic")){
+ rootNode.querySelector("button.statistic")!.setAttribute("data-percentage", percentage.toString());
+ rootNode.querySelector("button.statistic")!.setAttribute("data-remaining", tasksRemaining.toString());
+ }
+ if(rootNode.querySelector("#statisticDone"))
+ (rootNode.querySelector("#statisticDone") as HTMLElement)!.innerText = `✅ Done: ${done}/${taskCounter}`;
+ if(rootNode.querySelector("#statisticDue"))
+ (rootNode.querySelector("#statisticDue") as HTMLElement)!.innerText = `📅 Due: ${due}`;
+ if(rootNode.querySelector("#statisticOverdue"))
+ (rootNode.querySelector("#statisticOverdue") as HTMLElement)!.innerText = `⚠️ Overdue: ${overdue}`;
+ if(rootNode.querySelector("#statisticStart"))
+ (rootNode.querySelector("#statisticStart") as HTMLElement)!.innerText = `🛫 Start: ${start}`;
+ if(rootNode.querySelector("#statisticScheduled"))
+ (rootNode.querySelector("#statisticScheduled") as HTMLElement)!.innerText = `⏳ Scheduled: ${scheduled}`;
+ if(rootNode.querySelector("#statisticRecurrence"))
+ (rootNode.querySelector("#statisticRecurrence") as HTMLElement)!.innerText = `🔁 Recurrence: ${recurrence}`;
+ if(rootNode.querySelector("#statisticDailyNote"))
+ (rootNode.querySelector("#statisticDailyNote") as HTMLElement)!.innerText = `📄 Daily Notes: ${dailyNote}`;
+}
+
+const removeExistingView = (rootNode: HTMLElement) =>{
+ if (rootNode.querySelector(`.grid`)) {
+ rootNode.querySelector(`.grid`)!.remove();
+ } else if (rootNode.querySelector(`.list`)) {
+ rootNode.querySelector(`.list`)!.remove();
+ };
+};
+
+export { setStatisticPopUp, setWeekViewContext, setStatisticValues, removeExistingView };
+
+const transColor = (color: string, percent: number): string => {
+ let num = parseInt(color.replace("#", ""), 16);
+ let amt = Math.round(2.55 * percent);
+ let R = Math.min(255, Math.max(0, (num >> 16) + amt));
+ let G = Math.min(255, Math.max(0, (num >> 8 & 0x00FF) + amt));
+ let B = Math.min(255, Math.max(0, (num & 0x0000FF) + amt));
+ return `#${((1 << 24) + (R << 16) + (G << 8) + B).toString(16).slice(1).toUpperCase()}`;
+}
+
+const filterTasks = (task: any, date: any) => {
+ if(task.type == "overdue" && moment(date).isSame(moment(), 'day')){
+ return true;
+ }else if(task.type == "overdue" && moment(date).isBefore(moment(), 'day')){
+ return false;
+ }
+ if(task.recurrence){
+ return IsRecurringThisDay(task, date);
+ }else if(task.moment){
+ return task.moment.isSame(moment(date), "day");
+ }else{
+ return false;
+ }
+}
+
+const setTask = (obj: any, cls: string, dv: any) =>{
+ const lighter = 25;
+ const darker = -40;
+ const noteColor = getMetaFromNote(obj, "color", dv);
+ const textColor = getMetaFromNote(obj, "textColor", dv);
+ const noteIcon = getMetaFromNote(obj, "icon", dv);
+ const taskText = obj.text.replace("'", "'");
+ const taskPath = obj.link.path.replace("'", "'");
+ const relative = obj.due ? moment(obj.due).fromNow() : "";
+ const tasksubpath = obj.header.subpath;
+ const taskLine = tasksubpath ? taskPath+"#"+tasksubpath : taskPath;
+ let taskIcon = "";
+ let noteFilename = getFilename(taskPath);
+ let style;
+ if(cls.toLocaleLowerCase() == "done")
+ taskIcon = "✅";
+ else if(cls.toLocaleLowerCase() == "due")
+ taskIcon = "📅";
+ else if(cls.toLocaleLowerCase() == "scheduled")
+ taskIcon = "⏳";
+ else if(cls.toLocaleLowerCase() == "recurrence")
+ taskIcon = "🔁";
+ else if(cls.toLocaleLowerCase() == "overdue")
+ taskIcon = "⚠️";
+ else if(cls.toLocaleLowerCase() == "process")
+ taskIcon = "⏺️";
+ else if(cls.toLocaleLowerCase() == "cancelled")
+ taskIcon = "🚫";
+ else if(cls.toLocaleLowerCase() == "start")
+ taskIcon = "🛫";
+ else if(cls.toLocaleLowerCase() == "dailynote")
+ taskIcon = "📄";
+ else if(cls.toLocaleLowerCase() == "time" || (cls.toLocaleLowerCase() == "timepassed" && !obj.moment.isSame(moment(), 'day')))
+ taskIcon = "⌚";
+ else if(cls.toLocaleLowerCase() == "timepassed")
+ taskIcon = "⏰";
+ if(obj.type != cls){
+ cls += ` ${obj.type}`;
+ }
+
+ if (noteIcon) {
+ noteFilename = `${noteIcon} ${noteFilename}`;
+ } else {
+ noteFilename = `${taskIcon} ${noteFilename}`;
+ cls += " noNoteIcon";
+ }
+
+ const backgroundColor = noteColor ? `${noteColor}33` : `#7D7D7D33`;
+ const taskColor = noteColor || "#7D7D7D";
+ const darkTextColor = textColor || transColor(taskColor, darker);
+ const lightTextColor = textColor || transColor(taskColor, lighter);
+
+ style = `--task-background:${backgroundColor};--task-color:${taskColor};--dark-task-text-color:${darkTextColor};--light-task-text-color:${lightTextColor}`;
+
+ return taskTemplate(taskLine, cls, style, `${noteFilename}: ${taskText}`, noteFilename, taskIcon, relative, taskText);
+}
+
+const setStatisticPopUpEvents = (rootNode: HTMLElement) => {
+ rootNode.querySelectorAll('.statisticPopup li').forEach(li => li.addEventListener('click', (() => {
+ const group = li.getAttribute("data-group") as string;
+ const liElements = rootNode.querySelectorAll('.statisticPopup li');
+ const active = li.classList.contains("active");
+ for (const liElement of Array.from(liElements)) {
+ liElement.classList.remove('active');
+ }
+ if (active) {
+ rootNode.classList.remove("focus"+capitalize(group));
+ } else {
+ li.classList.add("active");
+ rootNode.classList.remove.apply(rootNode.classList, Array.from(rootNode.classList).filter(v=>v.startsWith("focus")));
+ rootNode.classList.add("focus"+capitalize(group));
+ }
+ })));
+}
+
+
+const setWeekViewContextEvents = (rootNode: HTMLElement) => {
+ rootNode.querySelectorAll('.weekViewContext li').forEach(li => li.addEventListener('click', (() => {
+ const selectedStyle = li.getAttribute("data-style")!;
+ if (!li.classList.contains("active")) {
+ for (const liElement of Array.from(rootNode.querySelectorAll('.weekViewContext li'))) {
+ liElement.classList.remove('active');
+ };
+ li.classList.add("active");
+ rootNode.classList.remove.apply(rootNode.classList, Array.from(rootNode.classList).filter(v=>v.startsWith("style")));
+ rootNode.classList.add(selectedStyle);
+ };
+ rootNode.querySelector(".weekViewContext")!.classList.toggle("active");
+ })));
+}
\ No newline at end of file
diff --git a/src/Tools/Timeline.ts b/src/Tools/Timeline.ts
new file mode 100644
index 0000000..abf6411
--- /dev/null
+++ b/src/Tools/Timeline.ts
@@ -0,0 +1,345 @@
+import { moment } from 'obsidian';
+import { getTime, getFilename, momentToRegex, isTime, isTimePassed } from 'src/Tools/Utils';
+// Icons
+const Icons = {
+ done: ' ',
+ due: ' ',
+ scheduled: ' ',
+ start: ' ',
+ overdue: ' ',
+ process: ' ',
+ dailynote: ' ',
+ unplanned: ' ',
+ task: ' ',
+ add: ' ',
+ tag: ' ',
+ repeat: ' ',
+ priority: ' ',
+ file: ' ',
+ forward: ' ',
+ alert: ' ',
+ cancelled: ' '
+}
+
+export { Icons };
+
+const getMeta = (tasks: any, input: {[name: string]: any}): Array => {
+ let {inbox, taskOrder, globalTaskFilter, dailyNoteFormat, done, forward, disableRecurrence, numberOfDays} = input;
+ if(!dailyNoteFormat)
+ dailyNoteFormat = "YYYY-MM-DD";
+ let today = moment().format("YYYY-MM-DD");
+ let dailyNoteRegEx = momentToRegex(dailyNoteFormat);
+ let timelineDates = [];
+ numberOfDays = numberOfDays || "1";
+ for(let i = 0; i < parseInt(numberOfDays); i++) {
+ timelineDates.push(moment(today).add(i, 'days').format("YYYY-MM-DD"));
+ }
+
+ dailyNoteFormat = dailyNoteFormat || "YYYY-MM-DD";
+ taskOrder = taskOrder || ["overdue", "due", "scheduled", "start", "done", "cancelled", "unplanned"];
+ for (let task of tasks) {
+ let happens: {[name: string]: string} = {};
+ let taskText = task.text;
+ let taskFile = getFilename(task.path);
+ let filePath = task.link.path;
+
+ // Inbox
+ if (inbox && inbox == filePath && task.completed == false && !taskText.match(/[🛫|⏳|📅|✅] *(\d{4}-\d{2}-\d{2})/)) {
+ happens["unplanned"] = today;
+ task.order = taskOrder.indexOf("unplanned");
+ };
+
+ // Daily Notes
+ let dailyNoteMatch = taskFile?.match(dailyNoteRegEx);
+ let dailyTaskMatch = taskText.match(/[🛫|⏳|📅|✅] *(\d{4}-\d{2}-\d{2})/);
+ if (dailyNoteMatch && task.completed == false && task.checked == false) {
+ task.dailyNote = true;
+ if(!dailyTaskMatch) {
+ if (moment(dailyNoteMatch[1], dailyNoteFormat).format("YYYY-MM-DD") < today) {
+ if (forward == true) {
+ happens["unplanned"] = today;
+ task.order = taskOrder.indexOf("unplanned");
+ } else {
+ happens["unplanned"] = moment(dailyNoteMatch[1], dailyNoteFormat).format("YYYY-MM-DD");
+ task.order = taskOrder.indexOf("unplanned");
+ };
+ } else {
+ happens["unplanned"] = moment(dailyNoteMatch[1], dailyNoteFormat).format("YYYY-MM-DD");
+ task.order = taskOrder.indexOf("unplanned");
+ };
+ };
+ } else if (dailyNoteMatch && task.completed == false && task.checked == true && moment(dailyNoteMatch[1], dailyNoteFormat).format("YYYY-MM-DD") >= today) {
+ happens["cancelled"] = moment(dailyNoteMatch[1], dailyNoteFormat).format("YYYY-MM-DD");
+ task.order = taskOrder.indexOf("cancelled");
+ } else if (dailyNoteMatch) {
+ task.dailyNote = true;
+ } else if (!dailyNoteMatch) {
+ task.dailyNote = false;
+ };
+
+ // Dataview Tasks
+ let inlineFields;
+ while (inlineFields = /\[([^\]]+)\:\:([^\]]+)\]/g.exec(task.text)) {
+ let inlineField = inlineFields[0];
+ let fieldKey = inlineFields[1].toLowerCase();
+ let fieldValue = inlineFields[2];
+ if ( fieldKey == "due" || fieldKey == "scheduled" || fieldKey == "start" || fieldKey == "completion") {
+ let fieldDate = moment(fieldValue).format("YYYY-MM-DD");
+ if (task.completed == false && task.checked == false) {
+ if ( fieldKey == "due" && fieldDate < today ) {
+ if (forward == true) {
+ happens["overdue"] = fieldDate;
+ happens["overdueForward"] = today;
+ task.order = taskOrder.indexOf("overdue");
+ } else {
+ happens["overdue"] = fieldDate;
+ task.order = taskOrder.indexOf("overdue");
+ };
+ } else if ( fieldKey == "due" && fieldDate == today ) {
+ happens["due"] = fieldDate;
+ task.order = taskOrder.indexOf("due");
+ } else if ( fieldKey == "due" && fieldDate > today ) {
+ happens["due"] = fieldDate;
+ task.order = taskOrder.indexOf("due");
+ };
+ if ( fieldKey == "scheduled" && fieldDate < today ) {
+ happens["scheduled"] = fieldDate;
+ happens["scheduledForward"] = today;
+ task.order = taskOrder.indexOf("scheduled");
+ } else if (fieldKey == "scheduled") {
+ happens["scheduled"] = fieldDate;
+ task.order = taskOrder.indexOf("scheduled");
+ };
+ if ( fieldKey == "start" && fieldDate < today ) {
+ happens["start"] = fieldDate;
+ happens["startForward"] = today;
+ task.order = taskOrder.indexOf("start");
+ } else if (fieldKey == "start") {
+ happens["start"] = fieldDate;
+ task.order = taskOrder.indexOf("start");
+ };
+ } else if (task.completed == true && task.checked == true) {
+ if (fieldKey == "completion") {
+ happens["done"] = fieldDate;
+ task.order = taskOrder.indexOf("done");
+ };
+ } else if (task.completed == false && task.checked == true && fieldDate >= today) {
+ happens["cancelled"] = fieldDate;
+ task.order = taskOrder.indexOf("cancelled");
+ };
+ };
+ task.text = task.text.replace(inlineField, "");
+ };
+
+ // Tasks Plugin Tasks
+ let dueMatch = taskText.match(/📅 *(\d{4}-\d{2}-\d{2})/);
+ if (dueMatch && task.completed == false && task.checked == false) {
+ task.text = task.text.replace(dueMatch[0], "");
+ task.moment = moment(dueMatch[1]);
+ task.test = dueMatch[1];
+ task.fullText = taskText;
+ if ( dueMatch[1] < today ) {
+ if (forward == true) {
+ happens["overdue"] = dueMatch[1];
+ happens["overdueForward"] = today;
+ task.order = taskOrder.indexOf("overdue");
+ } else {
+ happens["overdue"] = dueMatch[1];
+ task.order = taskOrder.indexOf("overdue");
+ };
+ } else if ( dueMatch[1] == today ) {
+ happens["due"] = dueMatch[1];
+ task.order = taskOrder.indexOf("due");
+ } else if ( dueMatch[1] > moment().format("YYYY-MM-DD") ) {
+ happens["due"] = dueMatch[1];
+ task.order = taskOrder.indexOf("due");
+ };
+ } else if (dueMatch && task.completed == true && task.checked == true) {
+ task.text = task.text.replace(dueMatch[0], "");
+ }
+ let scheduledMatch = taskText.match(/⏳ *(\d{4}-\d{2}-\d{2})/);
+ if (scheduledMatch && task.completed == false && task.checked == false) {
+ task.moment = moment(scheduledMatch[1]);
+ task.text = task.text.replace(scheduledMatch[0], "");
+ if ( scheduledMatch[1] < today ) {
+ happens["scheduled"] = scheduledMatch[1];
+ happens["scheduledForward"] = today;
+ task.order = taskOrder.indexOf("scheduled");
+ } else {
+ happens["scheduled"] = scheduledMatch[1];
+ task.order = taskOrder.indexOf("scheduled");
+ };
+ } else if (scheduledMatch && task.completed == true) {
+ task.text = task.text.replace(scheduledMatch[0], "");
+ };
+ if((dueMatch || scheduledMatch) && task.completed == false && task.checked == true) {
+ let timeMatch = dueMatch ? dueMatch : scheduledMatch;
+ task.text = task.text.replace(timeMatch[0], "");
+ happens["cancelled"] = timeMatch[1];
+ task.order = taskOrder.indexOf("cancelled");
+ task.done = true;
+ };
+ let startMatch = taskText.match(/🛫 *(\d{4}-\d{2}-\d{2})/);
+ if (startMatch && task.completed == false && task.checked == false) {
+ task.moment = moment(startMatch[1]);
+ task.text = task.text.replace(startMatch[0], "");
+ if ( startMatch[1] < today ) {
+ happens["start"] = startMatch[1];
+ happens["startForward"] = today;
+ task.order = taskOrder.indexOf("start");
+ } else {
+ happens["start"] = startMatch[1];
+ task.order = taskOrder.indexOf("start");
+ };
+ } else if (startMatch && task.completed == true) {
+ task.text = task.text.replace(startMatch[0], "");
+ };
+ let doneMatch = taskText.match(/✅ *(\d{4}-\d{2}-\d{2})/);
+ if (doneMatch && task.completed == true && task.checked == true) {
+ task.text = task.text.replace(doneMatch[0], "");
+ if (done == true || doneMatch[1] == today) {
+ happens["done"] = doneMatch[1];
+ task.order = taskOrder.indexOf("done");
+ }
+ task.done = true;
+ };
+ let repeatMatch = taskText.match(/🔁 ?([a-zA-Z0-9, !]+)/)
+ if (repeatMatch) {
+ let matchResult = taskText.match(/🔁\s*(.*?)\s*[🛫⏳📅⌚]/);
+ task.recurrence = true;
+ if(disableRecurrence != "true"){
+ task.recurringValue = matchResult ? matchResult[1] : "";
+ }
+ task.repeat = repeatMatch[1];
+ task.text = task.text.replace(repeatMatch[0], "");
+ };
+ let lowMatch = taskText.includes("🔽");
+ if (lowMatch) {
+ task.text = task.text.replace("🔽","");
+ task.priority = "D";
+ task.priorityLabel = "low priority";
+ };
+ let mediumMatch = taskText.includes("🔼");
+ if (mediumMatch) {
+ task.text = task.text.replace("🔼","");
+ task.priority = "B";
+ task.priorityLabel = "medium priority";
+ };
+ let highMatch = taskText.includes("⏫");
+ if (highMatch) {
+ task.text = task.text.replace("⏫","");
+ task.priority = "A";
+ task.priorityLabel = "high priority";
+ };
+ if (!lowMatch && !mediumMatch && !highMatch) {
+ task.priority = "C";
+ }
+ if (globalTaskFilter) {
+ task.text = task.text.replaceAll(globalTaskFilter,"");
+ } else {
+ task.text = task.text.replaceAll("#task","");
+ };
+
+ // Link Detection
+ let outerLink;
+ while (outerLink = /\[([^\]]+)\]\(([^)]+)\)/g.exec(task.text)) {
+ task.text = task.text.replace(outerLink[0], `${outerLink[1]} `);
+ };
+ let innerLink;
+ while (innerLink = /\[\[([^\]]+)\]\]/g.exec(task.text)) {
+ task.text = task.text.replace(innerLink[0], `${innerLink[1]} `);
+ };
+
+ // Markdown Highlights
+ let mark;
+ while (mark = /\=\=([^\]]+)\=\=/g.exec(task.text)) {
+ task.text = task.text.replace(mark[0], "" + mark[1] + " ");
+ };
+
+ // Reminder Syntax
+ let reminderMatch = taskText.match(/⏰ *(\d{4}-\d{2}-\d{2}) *(\d{2}\:\d{2})|⏰ *(\d{4}-\d{2}-\d{2})|(\(\@(\d{4}-\d{2}-\d{2}) *(\d{2}\:\d{2})\))|(\(\@(\d{4}-\d{2}-\d{2})\))/);
+ if (reminderMatch) {
+ task.text = task.text.replace(reminderMatch[0], "");
+ };
+ if(task.moment && isTime(task)){
+ let time = getTime(taskText).split(":");
+ task.moment.add(parseInt(time[0]), "hours").add(parseInt(time[1]), "minutes");
+ task.type = "time";
+ }
+ if(Object.keys(happens).includes("overdue") || Object.keys(happens).some(key => /Forward/.test(key))){
+ task.typePriority = 1;
+ }else if(isTimePassed(task)){
+ task.typePriority = 2;
+ }else if(!isTime(task) && (Object.keys(happens).includes("due") || Object.keys(happens).includes("scheduled"))){
+ task.typePriority = 3;
+ }else if(Object.keys(happens).includes("start")){
+ task.typePriority = 4;
+ }else if(isTime(task)){
+ task.typePriority = 5;
+ }else if(Object.keys(happens).includes("done")){
+ task.typePriority = 6;
+ }else if (Object.keys(happens).includes("cancelled")) {
+ task.typePriority = 7;
+ }
+
+ task.happens = happens;
+ };
+ return [...new Set(timelineDates)].sort();
+}
+
+const getRelative = (someDate: string) => {
+ let date = moment(someDate);
+ if (moment().diff(date, 'days') >= 1 || moment().diff(date, 'days') <= -1) {
+ return date.fromNow();
+ } else {
+ return date.calendar().split(' ')[0];
+ }
+}
+
+const getSelectOptions = (rootNode: HTMLElement, dailyNoteFolder: string, dailyNoteFormat: string, taskFiles:Array, inbox: string, select: string) => {
+ // Push daily note and Inbox files
+
+ if(!dailyNoteFormat)
+ dailyNoteFormat = "YYYY-MM-DD";
+ const currentDailyNote = dailyNoteFolder + moment().format(dailyNoteFormat) + ".md";
+ taskFiles.push(currentDailyNote);
+ if (inbox) {taskFiles.push(inbox)};
+ taskFiles = [...new Set(taskFiles)].sort();
+ // Loop files
+ const fileSelect = rootNode.querySelector('.fileSelect')!;
+ taskFiles.forEach(function(file) {
+ let opt = document.createElement('option');
+ opt.value = file;
+ let secondParentFolder = file.split("/")[file.split("/").length - 3] == null ? "" : "… / ";
+ let parentFolder = file.split("/")[file.split("/").length - 2] == null ? "" : `${secondParentFolder}📂 ${file.split("/")[file.split("/").length - 2]} / `;
+ let filePath = `${parentFolder}📄 ${getFilename(file)}`;
+ opt.innerHTML = filePath;
+ opt.title = file;
+ if (select && file == select) {
+ opt.setAttribute('selected', "true");
+ } else if (select && select == "dailyNote" && file == currentDailyNote) {
+ opt.setAttribute('selected', "true");
+ }
+ fileSelect.appendChild(opt);
+ });
+}
+
+const addNewTask = (fileText: string, newTask: string, section: string|undefined) => {
+ const newTaskText = `- [ ] ${newTask}`;
+ if (section != undefined) {
+ const lines = fileText.split("\n");
+ const index = lines.indexOf(section);
+ if (index != -1) {
+ lines.splice(index + 1, 0, newTaskText);
+ return lines.join("\n");
+ } else {
+ //@todo : replace confirm with a modal
+ if (confirm(`Section marker '${section}' not found. Would you like to create it?`) == true) {
+ return `${fileText.replace(/\n+$/, "")}\n\n${section}\n\n${newTaskText}`;
+ }
+ }
+ }
+ return `${fileText.replace(/\n+$/, "")}\n\n${newTaskText}`;
+}
+
+export { getMeta, getRelative, getSelectOptions, addNewTask };
\ No newline at end of file
diff --git a/src/Tools/Utils.ts b/src/Tools/Utils.ts
new file mode 100644
index 0000000..ec28a72
--- /dev/null
+++ b/src/Tools/Utils.ts
@@ -0,0 +1,103 @@
+import { moment } from "obsidian";
+import { RRule } from "rrule";
+
+/**
+ * Functions to filter tasks
+ */
+const taskNotCompleted = (t:any) => !t.completed && !t.fullyCompleted;
+const taskNotCancelled = (t:any) => t.status != "-";
+const isNotCompletedOrCancelled = (t: any) => taskNotCancelled(t) && taskNotCompleted(t);
+const isTodayTask = (t: any) => (t.due && moment(t.due.ts).isSame(moment(), 'day') || (t.scheduled && moment(t.scheduled.ts).isSame(moment(), 'day')));
+const hasTimeFormat = (t: any) => /⌚(\d{2}:\d{2})/.test(t.text);
+
+const getTime = (timeString : string) =>{
+ const time = timeString.match(/⌚(\d{2}:\d{2})/);
+ if(time && time[1])
+ return time![1];
+ else return "";
+}
+
+export { hasTimeFormat, getTime, isNotCompletedOrCancelled };
+
+const isTimeBeforeCurrentTime = (t: any) => {
+ const timeSubstring = getTime(t.text);
+ if (timeSubstring) {
+ return moment(timeSubstring, 'HH:mm').isBefore(moment());
+ }
+ // If any condition fails, return false
+ return false;
+}
+
+const getFilename = (path: string): string | undefined =>
+ (path.match(/^(?:.*\/)?([^\/]+?|)(?=(?:\.[^\/.]*)?$)/)||[])[1];
+const momentToRegex = (momentFormat: string) : string => {
+ momentFormat = momentFormat.replaceAll(".", "\\.");
+ momentFormat = momentFormat.replaceAll(",", "\\,");
+ momentFormat = momentFormat.replaceAll("-", "\\-");
+ momentFormat = momentFormat.replaceAll(":", "\\:");
+ momentFormat = momentFormat.replaceAll(" ", "\\s");
+
+ momentFormat = momentFormat.replace("dddd", "\\w{1,}");
+ momentFormat = momentFormat.replace("ddd", "\\w{1,3}");
+ momentFormat = momentFormat.replace("dd", "\\w{2}");
+ momentFormat = momentFormat.replace("d", "\\d{1}");
+
+ momentFormat = momentFormat.replace("YYYY", "\\d{4}");
+ momentFormat = momentFormat.replace("YY", "\\d{2}");
+
+ momentFormat = momentFormat.replace("MMMM", "\\w{1,}");
+ momentFormat = momentFormat.replace("MMM", "\\w{3}");
+ momentFormat = momentFormat.replace("MM", "\\d{2}");
+
+ momentFormat = momentFormat.replace("DDDD", "\\d{3}");
+ momentFormat = momentFormat.replace("DDD", "\\d{1,3}");
+ momentFormat = momentFormat.replace("DD", "\\d{2}");
+ momentFormat = momentFormat.replace("D", "\\d{1,2}");
+
+ momentFormat = momentFormat.replace("ww", "\\d{1,2}");
+
+ return `/^(${momentFormat})$/`;
+}
+
+const getMetaFromNote = (task: any, metaName: string, dv: any) =>
+ dv.pages(`"${task.link.path}"`)[metaName][0] || "";
+
+const IsRecurringThisDay = (task: any, date: any)=>{
+ if(!task.recurringValue)
+ return false;
+ if(moment(date).isBefore(task.moment, 'day'))
+ return false;
+ try{
+ let rule = new RRule({
+ ...RRule.fromText(task.recurringValue).origOptions,
+ dtstart: task.moment.set("hour",12).toDate()
+ });
+ let startOfDay = moment(date).startOf("day").toDate();
+ let endOfDay = moment(date).endOf("day").toDate();
+ let occurrences = rule.between(startOfDay, endOfDay);
+ return occurrences.length > 0;
+ }catch(e){
+ return false;
+ }
+
+}
+
+
+const isDueOrScheduled = (task: any) =>
+ isNotCompletedOrCancelled(task) && (task.due || task.scheduled);
+const isTime = (task: any) =>
+ isNotCompletedOrCancelled(task) && hasTimeFormat(task) && isDueOrScheduled(task);
+
+const isTimePassed = (task: any) =>
+ isNotCompletedOrCancelled(task) && isTodayTask(task) && isTimeBeforeCurrentTime(task);
+
+const sortTasks = (a: any, b: any) =>{
+ if(a.typePriority != b.typePriority){
+ return a.typePriority - b.typePriority;
+ }
+ if(a.type == "time" || a.type == "timePassed"){
+ return a.moment.diff(b.moment);
+ }
+ return a.priority - b.priority;
+}
+export {getFilename, momentToRegex, getMetaFromNote, IsRecurringThisDay, isDueOrScheduled, isTime, isTimePassed, sortTasks};
\ No newline at end of file
diff --git a/src/scss/_variables.scss b/src/scss/_variables.scss
new file mode 100644
index 0000000..2f47ccc
--- /dev/null
+++ b/src/scss/_variables.scss
@@ -0,0 +1,39 @@
+$color-red: var(--color-red);
+$icon-color: var(--icon-color);
+$icon-color-active: var(--icon-color-active);
+$background-secondary: var(--background-secondary);
+$nav-item-background-active: var(--nav-item-background-active);
+$text-normal: var(--text-normal);
+$text-faint: var(--text-faint);
+$task-background: var(--task-background);
+$task-color: var(--task-color);
+$background-modifier-hover: var(--background-modifier-hover);
+$interactive-accent-hsl: var(--interactive-accent-hsl);
+$light-task-text-color: var(--light-task-text-color);
+$dark-task-text-color: var(--dark-task-text-color);
+$background-modifier-active-hover:var(--background-modifier-active-hover);
+$icon-size:var(--icon-size);
+$icon-stroke:var(--icon-stroke);
+$background-primary:var(--background-primary);
+$focus-types: (
+ "focusDailyNote": "dailyNote",
+ "focusDone": "done",
+ "focusDue": "due",
+ "focusOverdue": "overdue",
+ "focusRecurrence": "recurrence",
+ "focusScheduled": "scheduled",
+ "focusStart": "start"
+);
+$overdue-color:#ff375f;
+$interactive-accent: var(--interactive-accent);
+$tag-color: var(--tag-color);
+$text-muted:var(--text-muted);
+$interactive-normal: var(--interactive-normal);
+$input-shadow: var(--input-shadow);
+$checkbox-border-color: var(--checkbox-border-color);
+$checkbox-size:var(--checkbox-size);
+$checkbox-border-color-hover:var(--checkbox-border-color-hover);
+$background-modifier-form-field:var(--background-modifier-form-field);
+$input-border-width:var(--input-border-width);
+$background-modifier-border:var(--background-modifier-border);
+$checkbox-marker-color:var(--checkbox-marker-color);
\ No newline at end of file
diff --git a/src/scss/calendar.scss b/src/scss/calendar.scss
new file mode 100644
index 0000000..7ea7a6b
--- /dev/null
+++ b/src/scss/calendar.scss
@@ -0,0 +1,822 @@
+ @use 'variables' as *;
+ @use 'sass:map';
+ @use 'sass:list';
+
+ .tasksCalendar {
+ margin-top: 20px;
+ span {
+ display: contents;
+ }
+ .buttons {
+ cursor: default;
+ display: flex;
+ flex-direction: row;
+ flex-wrap: nowrap;
+ height: 30px;
+ margin-bottom: 4px;
+ width: 100%;
+ }
+ button {
+ align-items: center;
+ background-color: transparent;
+ background: $background-secondary;
+ border-radius: 5px;
+ border: 1px solid $nav-item-background-active;
+ box-shadow: none;
+ color:$icon-color;
+ cursor: pointer;
+ display: inline-flex;
+ flex: 0;
+ font-size: 14px;
+ font-weight: normal;
+ height: 30px;
+ justify-content: center;
+ outline: none;
+ padding: 4px 6px;
+ user-select: none;
+ white-space: nowrap;
+
+ &:nth-child(2),
+ &:nth-child(3),
+ &:nth-child(6) {
+ border-bottom-right-radius: 0;
+ border-right: 0.5px solid $nav-item-background-active;
+ border-top-right-radius: 0;
+ margin-right: 0;
+ }
+
+ &:nth-child(3),
+ &:nth-child(4),
+ &:nth-child(7) {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+ border-left: 0.5px solid $nav-item-background-active;
+ margin-left: 0;
+ }
+
+
+ &:nth-child(1) {
+ margin-right: 4px;
+ }
+ &:nth-child(8) {
+ margin-left: 4px;
+ }
+
+ &.statistic {
+ position: relative;
+
+ svg {
+ stroke:$icon-color;
+ }
+
+ &[data-percentage="100"]:after {
+ display: none !important;
+ }
+
+ &:after {
+ background: $background-secondary;
+ border-radius: 50%;
+ border: 1px solid $nav-item-background-active;
+ color:$icon-color;
+ content: attr(data-remaining);
+ font-size: 9px;
+ font-weight: bold;
+ height: 14px;
+ line-height: 14px;
+ overflow: hidden;
+ position: absolute;
+ right: -8px;
+ text-align: center;
+ top: -8px;
+ width: 14px;
+ }
+ }
+ }
+ .current {
+ display: inline;
+ flex: 1;
+ margin: 0 4px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+
+ span {
+ &:first-child {
+ color:$icon-color;
+ font-weight: bold;
+ }
+ &:last-child {
+ color: $icon-color-active;
+ font-weight: normal;
+ }
+ }
+ }
+ svg {
+ height: $icon-size;
+ stroke-width: $icon-stroke;
+ width: $icon-size;
+ }
+ .statisticPopup {
+ right: 0;
+
+ &:before{
+ right: 5px;
+ top: -10px;
+ }
+ }
+ .weekViewContext {
+ left: 65px;
+ &:before {
+ left: 5px;
+ top: -10px;
+ }
+
+ .liIcon {
+ display: grid !important;
+ height: 18px;
+ margin-right: 5px;
+ padding: 2px;
+ width: 18px;
+
+ .box {
+ background:$icon-color;
+ border-radius: 1px;
+ display: grid;
+ margin: 0.5px;
+ overflow: hidden;
+ z-index: 1;
+ }
+ }
+
+ li.active .liIcon .box {
+ background: $icon-color-active !important;
+ }
+ }
+ .grid {
+ cursor: default;
+ height: 75vH;
+ overflow: hidden;
+ width: 100%;
+
+ &:has(.taskNumber) {
+ height: auto;
+ }
+ }
+ .list {
+ cursor: default;
+ height: 75vH;
+ overflow-x: hidden;
+ overflow-y: auto;
+ width: 100%;
+ }
+ .cell {
+ display: grid;
+ grid-template-columns: 1fr;
+ grid-template-rows: auto 1fr;
+ margin: 1px 0;
+ overflow: hidden;
+ z-index: 1;
+
+ &.today .cellName {
+ color: $text-normal;
+ font-weight: bold;
+ opacity: 1;
+ }
+
+ &[data-weekday="0"].today .cellName {
+ color: $icon-color-active;
+ font-weight: bold;
+ opacity: 1;
+ }
+ }
+ .cellContent {
+ align-content: start;
+ overflow-x: hidden;
+ overflow-y: auto;
+ padding: 1px 0;
+
+ &::-webkit-scrollbar {
+ display: none;
+ }
+ }
+ .cellName {
+ color: $text-normal;
+ display: block;
+ flex-grow: 0;
+ flex-shrink: 0;
+ font-size: 14px;
+ font-weight: normal;
+ margin: 0;
+ opacity: 0.8;
+ overflow: hidden;
+ padding: 0 2px;
+ text-align: left;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+ .task {
+ background: $task-background;
+ border-radius: 3px;
+ display: block;
+ font-size: 14px;
+ margin: 1px 1px 2px 1px;
+ opacity: 0.8;
+ overflow: hidden;
+ overflow: hidden;
+ padding: 1px;
+
+ &.hide {
+ opacity: 0.2;
+ }
+
+ .inner {
+ -webkit-box-orient: vertical;
+ -webkit-hyphens: none !important;
+ -webkit-line-clamp: 1;
+ border-radius: 3px;
+ display: -webkit-box;
+ line-height: 1.3;
+ overflow: hidden;
+ overflow: hidden;
+ text-decoration: none !important;
+ text-decoration: none;
+ text-overflow: ellipsis;
+ word-break: break-all !important;
+ }
+
+ .note {
+ background: $task-background;
+ display: block;
+ font-size: 9px;
+ overflow: hidden;
+ padding: 1px;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ width: 100%;
+ }
+
+ .icon {
+ display: inline;
+ height: 18px;
+ margin-right: 3px;
+ text-align: center;
+ width: 18px;
+ }
+
+ .description {
+ display: inline;
+ padding: 1px;
+
+ &:before {
+ border-radius: 3px;
+ content: attr(data-relative);
+ display: inline;
+ font-size: 9px;
+ margin-right: 3px;
+ margin-right: 3px;
+ padding: 0 3px;
+ vertical-align: middle;
+ }
+ }
+ &.overdue {
+ .description:before {
+ background: #ff443a;
+ color: white;
+ }
+ .inner {
+ background: repeating-linear-gradient(45deg, $task-background, $task-background 5px, transparent 5px, transparent 10px) !important;
+ }
+ }
+ &:not(.overdue) .description:before {
+ background: black;
+ color: white;
+ display: none;
+ }
+ &.dailyNote .description:before,
+ &.done .description:before,
+ &.cancelled .description:before {
+ display: none !important;
+ }
+ &.cancelled,
+ &.done {
+ background: none !important;
+
+ .note {
+ background: $nav-item-background-active !important;
+ color: $text-faint !important;
+ }
+ .description {
+ color: $text-faint !important;
+ text-decoration: line-through !important;
+ }
+ }
+ }
+ .taskNumber {
+ display:flex;
+ font-size: 30px;
+ font-weight: bold;
+ justify-content: center;
+ }
+ &.mini {
+ margin: 0 auto;
+ max-width: 500px !important;
+
+ .grid {
+ height: 400px !important;
+ }
+
+ .gridHead,
+ .cellName,
+ .task,
+ .wrapperButton {
+ font-size: 9px !important;
+ }
+
+ .wrappers:before,
+ .grid:before {
+ font-size: 70px !important;
+ }
+
+ .statisticPopup li,
+ .weekViewContext li {
+ font-size: 9px !important;
+ }
+ }
+ &.noWeekNr {
+ .wrapperButton,
+ .gridHead:first-child {
+ visibility: hidden !important;
+ width: 0 !important;
+ }
+
+ .wrapper,
+ .gridHeads {
+ grid-template-columns: 0px 1fr 1fr 1fr 1fr 1fr 1fr 1fr !important;
+ }
+ }
+ &.filter #statisticDone {
+ color: $text-faint !important;
+ pointer-events: none !important;
+ }
+ &.noCellNameEvent .cellName {
+ pointer-events: none !important;
+ }
+ &.lineClamp1 .task .inner {
+ -webkit-line-clamp: 1 !important;
+ white-space: nowrap !important;
+ }
+ &.lineClamp2 .task .inner {
+ -webkit-line-clamp: 2 !important;
+ }
+ &.lineClamp3 .task .inner {
+ -webkit-line-clamp: 3 !important;
+ }
+ &.noLineClamp .task .inner {
+ display: block !important;
+ }
+ a {
+ text-decoration: none !important;
+ }
+ summary {
+ &::marker,
+ &::-webkit-details-marker{
+ content: "" !important;
+ display: none !important;
+ }
+ }
+ .statisticPopup,
+ .weekViewContext {
+ background: $background-secondary;
+ border-radius: 5px;
+ border: 1px solid $nav-item-background-active;
+ box-shadow: 0px 0px 10px 0px $nav-item-background-active;
+ display: none;
+ font-size: 10px;
+ height: auto;
+ list-style: none;
+ margin: 0 !important;
+ padding: 2px !important;
+ position: absolute;
+ width: 150px;
+ width: auto;
+ z-index: 99;
+
+ &:before{
+ -webkit-transform:rotate(360deg);
+ border-color: transparent transparent $background-secondary transparent;
+ border-style: solid;
+ border-width: 0 10px 10px 10px;
+ content: "";
+ height: 0px;
+ position: absolute;
+ width: 0px;
+ }
+
+ &.active {
+ display: block;
+ }
+
+ li {
+ align-items: center;
+ border-radius: 5px;
+ color: $text-normal;
+ cursor: pointer;
+ display: flex;
+ flex-direction: row;
+ flex-wrap: nowrap;
+ font-size: 14px;
+ height: auto;
+ list-style: none;
+ padding: 5px 10px;
+
+ &.active {
+ background: $background-modifier-active-hover;
+ color: $icon-color-active !important;
+ }
+ &.break {
+ background: $nav-item-background-active;
+ border-radius: 0 !important;
+ height: 1px !important;
+ margin: 2px 5px !important;
+ padding: 0 !important;
+ }
+ }
+
+ > div {
+ height: 13px;
+ margin: auto 0;
+ }
+ }
+ .cell[data-weekday="0"] .cellName,
+ .gridHead[data-weekday="0"] {
+ color: $icon-color-active;
+ }
+ &.noIcons .task .icon,
+ &:not(.noFilename) .task.noNoteIcon .icon,
+ &.noFilename .task .note,
+ &.filter .task.done,
+ &.filter .task.cancelled,
+ &.noScheduled .task.scheduled,
+ &.noStart .task.start,
+ &.noDue .task.due,
+ &.noDone .task.done,
+ &.noProcess .task.process,
+ &.noRecurrence .task.recurrence,
+ &.noOverdue .task.overdue,
+ &.noDailyNote .task.dailyNote,
+ &.noLayer .grid .wrappers:before,
+ &.noLayer .grid:before,
+ &.noLayer .list:before,
+ &.noWeekNr .list .weekNr,
+ &.noOverdueFlag .task .description:before {
+ display: none !important;
+ }
+ &[data-weekday="0"].today .cellName {
+ color: $icon-color-active;
+ font-weight: bold;
+ opacity: 1;
+ }
+ &[view="week"] {
+ .cell {
+ border-radius: 5px;
+ border: 1px solid $nav-item-background-active;
+ overflow: hidden;
+
+ &.today {
+ background: $background-modifier-active-hover !important;
+ border: 1px solid hsla($interactive-accent-hsl, 0.25) !important;
+ }
+ }
+
+ .grid {
+ display: grid;
+ gap: 2px 4px;
+
+ &:before {
+ content: attr(data-week);
+ }
+ }
+
+ &.style11 {
+ .grid {
+ height: 300px;
+ }
+ .cell[data-weekday="0"],
+ .cell[data-weekday="6"] {
+ display: none !important;
+ }
+ }
+ }
+ &[view="month"] {
+ .grid {
+ display: grid;
+ gap: 4px;
+ grid-template-columns: 1fr !important;
+ grid-template-rows: 20px 1fr !important;
+ }
+
+ .gridHeads {
+ display: grid;
+ border-radius: 5px;
+ border: 1px solid $nav-item-background-active;
+ grid-template-columns: 20px 1fr 1fr 1fr 1fr 1fr 1fr 1fr !important;
+ height: 20px;
+ width: 100%;
+ }
+
+ .gridHead {
+ box-sizing: border-box;
+ display: inline;
+ font-size: 10px;
+ font-size: 14px;
+ font-weight: bold;
+ height: 20px;
+ line-height: 20px;
+ margin: 0;
+ overflow: hidden;
+ text-align: center;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+ .wrappers {
+ display: grid;
+ gap: 4px 4px;
+ grid-template-columns: 1fr !important;
+ grid-template-rows: repeat(6, calc(100% / 6));
+ height: calc(100% - 20px);
+ min-height: 0;
+ }
+ .wrapper {
+ border-radius: 5px;
+ border: 1px solid $nav-item-background-active;
+ display: grid;
+ grid-template-columns: 22px 1fr 1fr 1fr 1fr 1fr 1fr 1fr !important;
+ grid-template-rows: 1fr !important;
+ height: 100%;
+ overflow: hidden;
+ width: 100%;
+ z-index: 1;
+ }
+ .wrapperButton {
+ align-items: center;
+ background: none;
+ /* background: $background-primary; */
+ background: $background-secondary;
+ color: $text-normal;
+ color: $icon-color-active;
+ cursor: pointer;
+ display: flex;
+ font-size: 10px;
+ font-weight: normal;
+ justify-content: center;
+ overflow: hidden;
+ text-align: center;
+ transform: rotate(180deg);
+ width: 100%;
+ writing-mode: vertical-lr;
+
+ &:hover {
+ background: $background-modifier-hover;
+ }
+ }
+ .cell {
+ margin: 0;
+
+ &.today {
+ background: $background-modifier-active-hover !important;
+ border: 1px solid hsla($interactive-accent-hsl, 0.25) !important;
+ border-radius: 5px;
+ }
+ }
+ .prevMonth,
+ .nextMonth {
+ background: $background-secondary;
+ }
+ }
+ &[view="list"] {
+ .list {
+ border: 1px solid $nav-item-background-active;
+ border-radius: 5px;
+
+ .task {
+ .inner {
+ display: flex !important;
+ flex-direction: row;
+ flex-wrap: nowrap;
+ padding: 0 10px;
+ white-space: nowrap;
+ }
+
+ .note {
+ display: inline-block;
+ flex-grow: 0;
+ flex-shrink: 0;
+ width: 150px;
+ }
+
+ .description {
+ flex-grow: 1;
+ flex-shrink: 1;
+ width: 100%;
+ }
+
+ &.done .note,
+ &.done .description,
+ &.cancelled .note,
+ &.cancelled .description {
+ color: $text-faint !important;
+ }
+
+ &,
+ &.done,
+ .note,
+ &.done .note{
+ background: transparent !important;
+ }
+
+ .note,
+ .description {
+ color: $task-color !important;
+ font-size: 14px;
+ line-clamp: 0 !important;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap !important;
+ }
+ }
+ }
+
+ details {
+ /*background: $background-secondary;*/
+ border-radius: 5px;
+ border: 1px solid $nav-item-background-active;
+ display: block;
+ margin: 5px;
+
+ &.today {
+ background: $background-modifier-active-hover;
+ border: 1px solid hsla($interactive-accent-hsl, 0.25);
+
+ summary {
+ background: none;
+ font-weight: bold;
+ }
+
+ .content {
+ margin: 3px;
+ }
+ }
+ }
+
+ summary {
+ background: $background-secondary;
+ border-radius: 5px;
+ padding: 0 10px;
+
+ span.weekNr {
+ color: $text-faint;
+ font-size: 11px;
+ }
+ }
+ }
+ &[view="list"] button.listView,
+ &[view="week"] button.weekView,
+ &[view="month"] button.monthView,
+ &.filter button.filter {
+ background: $background-modifier-active-hover;
+ svg {
+ stroke: $icon-color-active !important;
+ }
+ }
+ &[view="month"] .wrappers,
+ &[view="week"] .grid {
+ position: relative;
+ }
+ &[view="month"] .wrappers:before,
+ &[view="week"] .grid:before,
+ &[view="list"] .list:before {
+ color: $background-modifier-active-hover;
+ font-size: 120px;
+ font-weight: bold;
+ left: 50%;
+ position: absolute;
+ top: 50%;
+ transform: translate(-50%, -50%);
+ z-index: 0;
+ }
+ &[view="month"] .wrappers:before,
+ &[view="list"] .list:before {
+ content: attr(data-month);
+ }
+ @each $focus, $task in $focus-types {
+ &.#{$focus} {
+ .task {
+ opacity: 0.25 !important;
+
+ &.#{$task} {
+ opacity: 1 !important;
+ }
+ }
+ }
+ }
+
+ }
+
+ .iconStyle11 {
+ display: none !important;
+ }
+
+ $styles: (
+ 1: (rows: repeat(6,1fr), cols: repeat(4,1fr)),
+ 2: (rows: repeat(6,1fr), cols: repeat(4,1fr)),
+ 3: (rows: repeat(7, 1fr), cols: 1fr),
+ 4: (rows: 1fr, cols: repeat(7, 1fr)),
+ 5: (rows: repeat(10, 1fr), cols: repeat(2, 1fr)),
+ 6: (rows: repeat(10, 1fr), cols: repeat(3, 1fr)),
+ 7: (rows: repeat(8, 1fr), cols: repeat(2, 1fr)),
+ 8: (rows: repeat(5, 1fr), cols: repeat(3, 1fr)),
+ 9: (rows: repeat(3, 1fr), cols: repeat(10, 1fr)),
+ 10: (rows: repeat(3, 1fr), cols: repeat(10, 1fr)),
+ 11: (rows: 1fr, cols: repeat(5, 1fr))
+ );
+ @each $style, $grid in $styles {
+ .tasksCalendar[view=week].style#{$style} .grid,
+ .iconStyle#{$style} {
+ grid-template-columns: map.get($grid, cols);
+ grid-template-rows: map.get($grid, rows);
+ }
+ }
+ @function grid-area($start-row, $start-col, $end-row, $end-col) {
+ @return #{$start-row} / #{$start-col} / #{$end-row} / #{$end-col};
+ }
+ @each $style, $areas in (
+ 1: (1: (1 1 3 2), 2: (3 1 5 3), 3: (5 1 7 3), 4: (1 3 3 5), 5: (3 3 5 5), 6: (5 3 6 5), 7: (6 3 7 5)),
+ 2: (1: (1 1 3 3), 2: (3 1 5 3), 3: (5 1 7 3), 4: (1 3 3 5), 5: (3 3 5 5), 6: (5 3 6 5), 7: (6 3 7 5)),
+ 5: (1: (1 1 3 2), 2: (3 1 5 2), 3: (5 1 7 2), 4: (7 1 9 2), 5: (9 1 11 2), 6: (1 2 6 3), 7: (6 2 11 3)),
+ 6: (1: (1 1 3 3), 2: (3 1 5 3), 3: (5 1 7 3), 4: (7 1 9 3), 5: (9 1 11 3), 6: (1 3 6 4), 7: (6 3 11 4)),
+ 7: (1: (1 1 3 2), 2: (3 1 5 2), 3: (5 1 7 2), 4: (7 1 9 2), 5: (1 2 3 3), 6: (3 2 6 3), 7: (6 2 9 3)),
+ 8: (1: (1 1 3 2), 2: (1 2 3 3), 3: (1 3 3 4), 4: (3 1 5 2), 5: (3 2 5 3), 6: (3 3 5 4), 7: (5 1 6 4)),
+ 9: (1: (1 1 3 3), 2: (1 3 3 5), 3: (1 5 3 7), 4: (1 7 3 9), 5: (1 9 3 11), 6: (3 1 4 6), 7: (3 6 4 11)),
+ 10: (1: (1 1 4 3), 2: (1 3 4 5), 3: (1 5 4 7), 4: (1 7 3 9), 5: (1 9 3 11), 6: (3 7 4 9), 7: (3 9 4 11))
+ ) {
+ @each $index, $area in $areas {
+ .tasksCalendar[view=week].style#{$style} .grid .cell:nth-child(#{$index}),
+ .iconStyle#{$style} .box:nth-child(#{$index}) {
+ grid-area: grid-area(list.nth($area, 1), list.nth($area, 2), list.nth($area, 3), list.nth($area, 4));
+ }
+ }
+ }
+
+ body{
+ &:not(.is-mobile) .tasksCalendar {
+ button.listView:hover,
+ button.weekView:hover,
+ button.monthView:hover,
+ button.previous:hover,
+ button.next:hover,
+ button.current:hover,
+ button.filter:hover,
+ button.statistic:hover {
+ background: $background-modifier-hover;
+ }
+ .statisticPopup li:not(.active):hover,
+ .weekViewContext li:not(.active):hover {
+ background: $background-modifier-hover;
+ }
+ .cellName:hover {
+ opacity: 1;
+ }
+ .task:hover {
+ opacity: 1;
+ }
+ }
+ &.theme-dark .tasksCalendar .task {
+ color: $light-task-text-color;
+
+ .note {
+ color: $light-task-text-color;
+ }
+ }
+ &.theme-light .tasksCalendar .task {
+ color: $dark-task-text-color;
+
+ .note {
+ color: $dark-task-text-color;
+ }
+ }
+ &.is-mobile .tasksCalendar {
+ .gridHead,
+ .cellName,
+ .task {
+ font-size: 9px;
+ }
+
+ &[view="week"]:not(.style4) .cellName,
+ &[view="week"]:not(.style4) .task {
+ font-size: 13px !important;
+ }
+ .statisticPopup li {
+ font-size: 13px !important;
+ }
+ }
+ }
\ No newline at end of file
diff --git a/src/scss/style.scss b/src/scss/style.scss
new file mode 100644
index 0000000..c14b674
--- /dev/null
+++ b/src/scss/style.scss
@@ -0,0 +1,2 @@
+@use 'calendar';
+@use 'timeline';
\ No newline at end of file
diff --git a/src/scss/timeline.scss b/src/scss/timeline.scss
new file mode 100644
index 0000000..6ca2f30
--- /dev/null
+++ b/src/scss/timeline.scss
@@ -0,0 +1,477 @@
+ @use 'variables' as *;
+ .taskido {
+ cursor: default;
+ user-select: none;
+
+ .task {
+ border-radius: 10px;
+ cursor: pointer;
+ display: flex;
+ flex-direction: row;
+ flex-wrap: nowrap;
+ margin: 0;
+ padding: 0;
+
+ &.overdue {
+ .timeline .icon svg line {
+ stroke-width: 2.5px !important;
+ stroke: $overdue-color !important;
+ }
+
+ .info .relative {
+ color: $overdue-color !important;
+ }
+ }
+
+ &.done {
+ .timeline .icon svg {
+ fill: $interactive-accent !important;
+ stroke: $interactive-accent !important;
+
+ path:nth-child(1) {
+ fill: $interactive-accent !important;
+ }
+ path:nth-child(2) {
+ stroke-width: 2.5px;
+ stroke: $checkbox-marker-color !important;
+ }
+ }
+ }
+
+ .content {
+ color: $text-normal;
+ display: block;
+ font-size: 15px;
+ font-weight: normal;
+ line-height: 22px;
+ white-space: break-word;
+ }
+
+ .info {
+ cursor: default;
+ line-height: 22px;
+ padding-bottom: 2px;
+
+ &:empty {
+ display: none;
+ }
+
+ .file {
+ color: $task-color;
+ }
+
+ .tag {
+ background: none !important;
+ color: $tag-color !important;
+ cursor: pointer;
+ }
+
+ .icon {
+ height: 15px;
+ text-align: center;
+ }
+
+ .label {
+ margin-left: 2px;
+ }
+
+ svg {
+ height: 12px;
+ stroke-width: 1.75px;
+ width: 12px;
+ }
+ .tag,
+ .repeat,
+ .priority,
+ .relative,
+ .file {
+ align-items: center;
+ border-radius: 3px !important;
+ border: none;
+ color: var(--text-muted);
+ display: flex;
+ flex-direction: row;
+ flex-wrap: nowrap;
+ font-size: 9px;
+ font-weight: normal;
+ line-height: 1 !important;
+ margin: 2px 5px 2px 0;
+ padding: 0;
+ padding: 0px;
+ width: auto;
+ }
+
+ }
+
+ &.done,
+ &.cancelled {
+ .info {
+ .tag,
+ .repeat,
+ .priority,
+ .relative,
+ .file {
+ color: $text-muted !important;
+ line-height: 0;
+ }
+ }
+
+ .content {
+ color: $text-muted;
+ text-decoration: line-through;
+ }
+ }
+ .innerLink,
+ .outerLink {
+ color: $interactive-accent;
+ text-decoration: underline !important;
+ }
+ }
+ .info {
+ .icon {
+ text-align: center;
+ height: 15px;
+ }
+ .label {
+ margin-left: 2px;
+ }
+ svg {
+ height: 12px;
+ width: 12px;
+ stroke-width: 1.75px;
+ }
+ }
+ .year {
+ color: $text-normal;
+ font-size: 30px;
+ font-weight: bold;
+ margin: 20px 0;
+ text-align: center;
+ }
+ .details {
+ display: flex;
+ flex-direction: column;
+ flex-wrap: nowrap;
+ height: auto;
+ width: 100%;
+
+ .today {
+ padding: 30px 0;
+ }
+ }
+ .todayFocus{
+ .todayHeader {
+ color: $interactive-accent;
+ }
+
+ .details:not(.today),
+ .year {
+ display: none !important;
+ }
+
+ .details.today {
+ padding: 0;
+ }
+ }
+ .todayHeader {
+ border-radius: 10px;
+ cursor: pointer;
+ font-size: 24px;
+ font-weight: bold;
+ margin: 10px 5px;
+ text-align: center;
+ }
+ .counters {
+ align-content: center;
+ display: flex;
+ flex-direction: row;
+ flex-wrap: nowrap;
+ justify-content: center;
+ margin: 20px 0;
+ }
+ .counter {
+ background: $interactive-normal;
+ border-radius: 10px;
+ box-shadow: $input-shadow;
+ color: $text-normal;
+ cursor: pointer;
+ display: flex;
+ flex-direction: column;
+ flex-wrap: nowrap;
+ flex: 1 1 0;
+ margin: 0 5px;
+ max-width: 150px;
+ min-width: 70px;
+ overflow: hidden;
+ padding: 5px;
+ text-align: center;
+
+ .label {
+ font-size: 12px;
+ font-weight: normal;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+ }
+ .count {
+ font-size: 18px;
+ font-weight: normal;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+ .dateLine {
+ align-items: center;
+ display: flex;
+ flex-direction: row;
+ flex-wrap: nowrap;
+ justify-content: space-between;
+ margin: 10px 0;
+ }
+ .date {
+ color: $text-normal;
+ font-size: 16px;
+ font-weight: bold;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+ .weekday {
+ color: $text-normal;
+ font-size: 16px;
+ font-weight: normal;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+ .timeline {
+ flex-grow: 0;
+ flex-shrink: 0;
+ width: 50px;
+
+ .icon {
+ height: 22px;
+ text-align: center;
+
+ svg {
+ color: $checkbox-border-color;
+ height: $checkbox-size;
+ stroke-width: 1.75px;
+ width: $checkbox-size;
+ &:hover {
+ color: $checkbox-border-color-hover;
+ }
+ }
+ }
+ }
+ .lines {
+ flex-grow: 1;
+ flex-shrink: 1;
+ overflow: hidden;
+ }
+ .line {
+ align-items: center;
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ }
+ .stripe {
+ align-items: center;
+ background: $checkbox-border-color;
+ display: flex;
+ flex-grow: 1;
+ flex-shrink: 1;
+ justify-content: center;
+ margin: 0 auto;
+ width: 1px;
+ }
+ .icon {
+ align-items: center;
+ display: flex;
+ flex-grow: 0;
+ flex-shrink: 0;
+ justify-content: center;
+ text-align: center;
+ }
+ .quickEntryPanel {
+ background: $background-modifier-form-field;
+ border-radius: 10px;
+ border: $input-border-width solid $background-modifier-border;
+ box-shadow: 0 0 5px 0 rgba(0,0,0,0.1);
+ color: $text-normal;
+ display: flex;
+ flex-direction: row;
+ flex-wrap: nowrap;
+ margin: 0 5px 20px 5px;
+ overflow: hidden;
+ padding: 5px;
+
+ .left {
+ align-items: center;
+ border-radius: 5px;
+ display: flex;
+ flex-direction: column;
+ flex-grow: 1;
+ flex-shrink: 1;
+ flex-wrap: nowrap;
+ overflow: hidden;
+ padding: 0 5px !important;
+ width: 100%;
+ }
+
+ .right {
+ border-radius: 5px;
+ display: block;
+ flex-grow: 1;
+ flex-shrink: 1;
+ overflow: hidden;
+ width: auto;
+ }
+
+ input {
+ cursor: text;
+ font-size: 14px;
+ height: 20px;
+ line-height: 20px;
+ margin: 0 !important;
+ overflow: hidden;
+ padding: 0 !important;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ width: 100%;
+ }
+
+ select {
+ color: $text-muted;
+ font-size: 11px;
+ height: 15px;
+ margin: 2.5px 0 !important;
+ overflow: hidden;
+ padding: 0 !important;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ width: 100%;
+
+ option,
+ optgroup {
+ background: $background-primary;
+ color: $text-normal;
+ font-weight: normal;
+ }
+ }
+
+ button {
+ align-items: center;
+ color: $text-muted;
+ display: flex;
+ flex-direction: row;
+ flex-wrap: nowrap;
+ height: 100%;
+ justify-content: center;
+ margin: 0 !important;
+ padding: 0 5px !important;
+ width: auto;
+ }
+
+ svg {
+ height: 15px;
+ stroke-width: 1.75px;
+ width: 15px;
+ }
+
+ select,
+ input,
+ button {
+ background: none !important;
+ border-radius: 0 !important;
+ border: none !important;
+ box-shadow: none !important;
+
+ &:active {
+ border: none !important;
+ box-shadow: none !important;
+ transition: none !important;
+ }
+ }
+ select,
+ button {
+ cursor: pointer;
+
+ &:hover {
+ color: $text-normal;
+ }
+ }
+ }
+ .noColor .task {
+ .file {
+ color: $text-muted !important
+ }
+ .info .file {
+ color: $text-muted !important
+ }
+ }
+ a {
+ color: inherit !important;
+ text-decoration: none !important;
+ }
+ span {
+ display: contents;
+ }
+ .timeline,
+ .lines {
+ cursor: default;
+ display: flex;
+ flex-direction: column;
+ flex-wrap: nowrap;
+ }
+ .todoFocus .counter#todo,
+ .todoFilter .counter#todo,
+ .overdueFocus .counter#overdue,
+ .overdueFilter .counter#overdue,
+ .unplannedFocus .counter#unplanned,
+ .unplannedFilter .counter#unplanned {
+ background: hsla($interactive-accent-hsl, 0.2);
+ box-shadow: $input-shadow;
+ color: $interactive-accent;
+ }
+ .noYear .year,
+ .noRepeat .repeat,
+ .noTag .tag,
+ .noPriority .priority,
+ .noFile .task .file,
+ .noHeader .task .header,
+ .noFile .task .info > .file,
+ .noInfo .task .line:nth-child(2),
+ .noDone .year[data-types="done"],
+ .noDone .details[data-types="done"],
+ .noDone .task.done,
+ .noUnplanned .task.unplanned,
+ .noUnplanned .counter#unplanned,
+ .noUnplanned .year[data-types="unplanned"],
+ .noUnplanned .details[data-types="unplanned"],
+ .noRelative .relative,
+ .noQuickEntry .quickEntryPanel,
+ .noCounters .counters {
+ display: none !important;
+ }
+ .todoFocus .details.today .task.due,
+ .todoFocus .details.today .task.scheduled,
+ .todoFocus .details.today .task.process,
+ .todoFocus .details.today .task.start,
+ .overdueFocus .task.overdue,
+ .unplannedFocus .task.unplanned {
+ background: hsla($interactive-accent-hsl, 0.2);
+ }
+ .todoFilter .year:not(.current):not([data-types*="due"][data-types*="scheduled"][data-types*="overdue"]),
+ .todoFilter .details:not(.today):not([data-types*="due"][data-types*="scheduled"][data-types*="overdue"]),
+ .todoFilter .task:not(.due, .scheduled, .process, .start),
+ .overdueFilter .year:not(.current):not([data-types*="overdue"]),
+ .overdueFilter .details:not(.today):not([data-types*="overdue"]),
+ .overdueFilter .task:not(.overdue),
+ .unplannedFilter .year:not(.current):not([data-types*="unplanned"]),
+ .unplannedFilter .details:not(.today):not([data-types*="unplanned"]),
+ .unplannedFilter .task:not(.unplanned) {
+ display: none;
+ }
+ }
\ No newline at end of file
diff --git a/styles.css b/styles.css
new file mode 100644
index 0000000..46d00df
--- /dev/null
+++ b/styles.css
@@ -0,0 +1,1479 @@
+.tasksCalendar {
+ margin-top: 20px;
+}
+.tasksCalendar span {
+ display: contents;
+}
+.tasksCalendar .buttons {
+ cursor: default;
+ display: flex;
+ flex-direction: row;
+ flex-wrap: nowrap;
+ height: 30px;
+ margin-bottom: 4px;
+ width: 100%;
+}
+.tasksCalendar button {
+ align-items: center;
+ background-color: transparent;
+ background: var(--background-secondary);
+ border-radius: 5px;
+ border: 1px solid var(--nav-item-background-active);
+ box-shadow: none;
+ color: var(--icon-color);
+ cursor: pointer;
+ display: inline-flex;
+ flex: 0;
+ font-size: 14px;
+ font-weight: normal;
+ height: 30px;
+ justify-content: center;
+ outline: none;
+ padding: 4px 6px;
+ user-select: none;
+ white-space: nowrap;
+}
+.tasksCalendar button:nth-child(2), .tasksCalendar button:nth-child(3), .tasksCalendar button:nth-child(6) {
+ border-bottom-right-radius: 0;
+ border-right: 0.5px solid var(--nav-item-background-active);
+ border-top-right-radius: 0;
+ margin-right: 0;
+}
+.tasksCalendar button:nth-child(3), .tasksCalendar button:nth-child(4), .tasksCalendar button:nth-child(7) {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+ border-left: 0.5px solid var(--nav-item-background-active);
+ margin-left: 0;
+}
+.tasksCalendar button:nth-child(1) {
+ margin-right: 4px;
+}
+.tasksCalendar button:nth-child(8) {
+ margin-left: 4px;
+}
+.tasksCalendar button.statistic {
+ position: relative;
+}
+.tasksCalendar button.statistic svg {
+ stroke: var(--icon-color);
+}
+.tasksCalendar button.statistic[data-percentage="100"]:after {
+ display: none !important;
+}
+.tasksCalendar button.statistic:after {
+ background: var(--background-secondary);
+ border-radius: 50%;
+ border: 1px solid var(--nav-item-background-active);
+ color: var(--icon-color);
+ content: attr(data-remaining);
+ font-size: 9px;
+ font-weight: bold;
+ height: 14px;
+ line-height: 14px;
+ overflow: hidden;
+ position: absolute;
+ right: -8px;
+ text-align: center;
+ top: -8px;
+ width: 14px;
+}
+.tasksCalendar .current {
+ display: inline;
+ flex: 1;
+ margin: 0 4px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+.tasksCalendar .current span:first-child {
+ color: var(--icon-color);
+ font-weight: bold;
+}
+.tasksCalendar .current span:last-child {
+ color: var(--icon-color-active);
+ font-weight: normal;
+}
+.tasksCalendar svg {
+ height: var(--icon-size);
+ stroke-width: var(--icon-stroke);
+ width: var(--icon-size);
+}
+.tasksCalendar .statisticPopup {
+ right: 0;
+}
+.tasksCalendar .statisticPopup:before {
+ right: 5px;
+ top: -10px;
+}
+.tasksCalendar .weekViewContext {
+ left: 65px;
+}
+.tasksCalendar .weekViewContext:before {
+ left: 5px;
+ top: -10px;
+}
+.tasksCalendar .weekViewContext .liIcon {
+ display: grid !important;
+ height: 18px;
+ margin-right: 5px;
+ padding: 2px;
+ width: 18px;
+}
+.tasksCalendar .weekViewContext .liIcon .box {
+ background: var(--icon-color);
+ border-radius: 1px;
+ display: grid;
+ margin: 0.5px;
+ overflow: hidden;
+ z-index: 1;
+}
+.tasksCalendar .weekViewContext li.active .liIcon .box {
+ background: var(--icon-color-active) !important;
+}
+.tasksCalendar .grid {
+ cursor: default;
+ height: 75vH;
+ overflow: hidden;
+ width: 100%;
+}
+.tasksCalendar .grid:has(.taskNumber) {
+ height: auto;
+}
+.tasksCalendar .list {
+ cursor: default;
+ height: 75vH;
+ overflow-x: hidden;
+ overflow-y: auto;
+ width: 100%;
+}
+.tasksCalendar .cell {
+ display: grid;
+ grid-template-columns: 1fr;
+ grid-template-rows: auto 1fr;
+ margin: 1px 0;
+ overflow: hidden;
+ z-index: 1;
+}
+.tasksCalendar .cell.today .cellName {
+ color: var(--text-normal);
+ font-weight: bold;
+ opacity: 1;
+}
+.tasksCalendar .cell[data-weekday="0"].today .cellName {
+ color: var(--icon-color-active);
+ font-weight: bold;
+ opacity: 1;
+}
+.tasksCalendar .cellContent {
+ align-content: start;
+ overflow-x: hidden;
+ overflow-y: auto;
+ padding: 1px 0;
+}
+.tasksCalendar .cellContent::-webkit-scrollbar {
+ display: none;
+}
+.tasksCalendar .cellName {
+ color: var(--text-normal);
+ display: block;
+ flex-grow: 0;
+ flex-shrink: 0;
+ font-size: 14px;
+ font-weight: normal;
+ margin: 0;
+ opacity: 0.8;
+ overflow: hidden;
+ padding: 0 2px;
+ text-align: left;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+.tasksCalendar .task {
+ background: var(--task-background);
+ border-radius: 3px;
+ display: block;
+ font-size: 14px;
+ margin: 1px 1px 2px 1px;
+ opacity: 0.8;
+ overflow: hidden;
+ overflow: hidden;
+ padding: 1px;
+}
+.tasksCalendar .task.hide {
+ opacity: 0.2;
+}
+.tasksCalendar .task .inner {
+ -webkit-box-orient: vertical;
+ -webkit-hyphens: none !important;
+ -webkit-line-clamp: 1;
+ border-radius: 3px;
+ display: -webkit-box;
+ line-height: 1.3;
+ overflow: hidden;
+ overflow: hidden;
+ text-decoration: none !important;
+ text-decoration: none;
+ text-overflow: ellipsis;
+ word-break: break-all !important;
+}
+.tasksCalendar .task .note {
+ background: var(--task-background);
+ display: block;
+ font-size: 9px;
+ overflow: hidden;
+ padding: 1px;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ width: 100%;
+}
+.tasksCalendar .task .icon {
+ display: inline;
+ height: 18px;
+ margin-right: 3px;
+ text-align: center;
+ width: 18px;
+}
+.tasksCalendar .task .description {
+ display: inline;
+ padding: 1px;
+}
+.tasksCalendar .task .description:before {
+ border-radius: 3px;
+ content: attr(data-relative);
+ display: inline;
+ font-size: 9px;
+ margin-right: 3px;
+ margin-right: 3px;
+ padding: 0 3px;
+ vertical-align: middle;
+}
+.tasksCalendar .task.overdue .description:before {
+ background: #ff443a;
+ color: white;
+}
+.tasksCalendar .task.overdue .inner {
+ background: repeating-linear-gradient(45deg, var(--task-background), var(--task-background) 5px, transparent 5px, transparent 10px) !important;
+}
+.tasksCalendar .task:not(.overdue) .description:before {
+ background: black;
+ color: white;
+ display: none;
+}
+.tasksCalendar .task.dailyNote .description:before, .tasksCalendar .task.done .description:before, .tasksCalendar .task.cancelled .description:before {
+ display: none !important;
+}
+.tasksCalendar .task.cancelled, .tasksCalendar .task.done {
+ background: none !important;
+}
+.tasksCalendar .task.cancelled .note, .tasksCalendar .task.done .note {
+ background: var(--nav-item-background-active) !important;
+ color: var(--text-faint) !important;
+}
+.tasksCalendar .task.cancelled .description, .tasksCalendar .task.done .description {
+ color: var(--text-faint) !important;
+ text-decoration: line-through !important;
+}
+.tasksCalendar .taskNumber {
+ display: flex;
+ font-size: 30px;
+ font-weight: bold;
+ justify-content: center;
+}
+.tasksCalendar.mini {
+ margin: 0 auto;
+ max-width: 500px !important;
+}
+.tasksCalendar.mini .grid {
+ height: 400px !important;
+}
+.tasksCalendar.mini .gridHead,
+.tasksCalendar.mini .cellName,
+.tasksCalendar.mini .task,
+.tasksCalendar.mini .wrapperButton {
+ font-size: 9px !important;
+}
+.tasksCalendar.mini .wrappers:before,
+.tasksCalendar.mini .grid:before {
+ font-size: 70px !important;
+}
+.tasksCalendar.mini .statisticPopup li,
+.tasksCalendar.mini .weekViewContext li {
+ font-size: 9px !important;
+}
+.tasksCalendar.noWeekNr .wrapperButton,
+.tasksCalendar.noWeekNr .gridHead:first-child {
+ visibility: hidden !important;
+ width: 0 !important;
+}
+.tasksCalendar.noWeekNr .wrapper,
+.tasksCalendar.noWeekNr .gridHeads {
+ grid-template-columns: 0px 1fr 1fr 1fr 1fr 1fr 1fr 1fr !important;
+}
+.tasksCalendar.filter #statisticDone {
+ color: var(--text-faint) !important;
+ pointer-events: none !important;
+}
+.tasksCalendar.noCellNameEvent .cellName {
+ pointer-events: none !important;
+}
+.tasksCalendar.lineClamp1 .task .inner {
+ -webkit-line-clamp: 1 !important;
+ white-space: nowrap !important;
+}
+.tasksCalendar.lineClamp2 .task .inner {
+ -webkit-line-clamp: 2 !important;
+}
+.tasksCalendar.lineClamp3 .task .inner {
+ -webkit-line-clamp: 3 !important;
+}
+.tasksCalendar.noLineClamp .task .inner {
+ display: block !important;
+}
+.tasksCalendar a {
+ text-decoration: none !important;
+}
+.tasksCalendar summary::marker, .tasksCalendar summary::-webkit-details-marker {
+ content: "" !important;
+ display: none !important;
+}
+.tasksCalendar .statisticPopup,
+.tasksCalendar .weekViewContext {
+ background: var(--background-secondary);
+ border-radius: 5px;
+ border: 1px solid var(--nav-item-background-active);
+ box-shadow: 0px 0px 10px 0px var(--nav-item-background-active);
+ display: none;
+ font-size: 10px;
+ height: auto;
+ list-style: none;
+ margin: 0 !important;
+ padding: 2px !important;
+ position: absolute;
+ width: 150px;
+ width: auto;
+ z-index: 99;
+}
+.tasksCalendar .statisticPopup:before,
+.tasksCalendar .weekViewContext:before {
+ -webkit-transform: rotate(360deg);
+ border-color: transparent transparent var(--background-secondary) transparent;
+ border-style: solid;
+ border-width: 0 10px 10px 10px;
+ content: "";
+ height: 0px;
+ position: absolute;
+ width: 0px;
+}
+.tasksCalendar .statisticPopup.active,
+.tasksCalendar .weekViewContext.active {
+ display: block;
+}
+.tasksCalendar .statisticPopup li,
+.tasksCalendar .weekViewContext li {
+ align-items: center;
+ border-radius: 5px;
+ color: var(--text-normal);
+ cursor: pointer;
+ display: flex;
+ flex-direction: row;
+ flex-wrap: nowrap;
+ font-size: 14px;
+ height: auto;
+ list-style: none;
+ padding: 5px 10px;
+}
+.tasksCalendar .statisticPopup li.active,
+.tasksCalendar .weekViewContext li.active {
+ background: var(--background-modifier-active-hover);
+ color: var(--icon-color-active) !important;
+}
+.tasksCalendar .statisticPopup li.break,
+.tasksCalendar .weekViewContext li.break {
+ background: var(--nav-item-background-active);
+ border-radius: 0 !important;
+ height: 1px !important;
+ margin: 2px 5px !important;
+ padding: 0 !important;
+}
+.tasksCalendar .statisticPopup > div,
+.tasksCalendar .weekViewContext > div {
+ height: 13px;
+ margin: auto 0;
+}
+.tasksCalendar .cell[data-weekday="0"] .cellName,
+.tasksCalendar .gridHead[data-weekday="0"] {
+ color: var(--icon-color-active);
+}
+.tasksCalendar.noIcons .task .icon, .tasksCalendar:not(.noFilename) .task.noNoteIcon .icon, .tasksCalendar.noFilename .task .note, .tasksCalendar.filter .task.done, .tasksCalendar.filter .task.cancelled, .tasksCalendar.noScheduled .task.scheduled, .tasksCalendar.noStart .task.start, .tasksCalendar.noDue .task.due, .tasksCalendar.noDone .task.done, .tasksCalendar.noProcess .task.process, .tasksCalendar.noRecurrence .task.recurrence, .tasksCalendar.noOverdue .task.overdue, .tasksCalendar.noDailyNote .task.dailyNote, .tasksCalendar.noLayer .grid .wrappers:before, .tasksCalendar.noLayer .grid:before, .tasksCalendar.noLayer .list:before, .tasksCalendar.noWeekNr .list .weekNr, .tasksCalendar.noOverdueFlag .task .description:before {
+ display: none !important;
+}
+.tasksCalendar[data-weekday="0"].today .cellName {
+ color: var(--icon-color-active);
+ font-weight: bold;
+ opacity: 1;
+}
+.tasksCalendar[view=week] .cell {
+ border-radius: 5px;
+ border: 1px solid var(--nav-item-background-active);
+ overflow: hidden;
+}
+.tasksCalendar[view=week] .cell.today {
+ background: var(--background-modifier-active-hover) !important;
+ border: 1px solid hsla(var(--interactive-accent-hsl), 0.25) !important;
+}
+.tasksCalendar[view=week] .grid {
+ display: grid;
+ gap: 2px 4px;
+}
+.tasksCalendar[view=week] .grid:before {
+ content: attr(data-week);
+}
+.tasksCalendar[view=week].style11 .grid {
+ height: 300px;
+}
+.tasksCalendar[view=week].style11 .cell[data-weekday="0"],
+.tasksCalendar[view=week].style11 .cell[data-weekday="6"] {
+ display: none !important;
+}
+.tasksCalendar[view=month] .grid {
+ display: grid;
+ gap: 4px;
+ grid-template-columns: 1fr !important;
+ grid-template-rows: 20px 1fr !important;
+}
+.tasksCalendar[view=month] .gridHeads {
+ display: grid;
+ border-radius: 5px;
+ border: 1px solid var(--nav-item-background-active);
+ grid-template-columns: 20px 1fr 1fr 1fr 1fr 1fr 1fr 1fr !important;
+ height: 20px;
+ width: 100%;
+}
+.tasksCalendar[view=month] .gridHead {
+ box-sizing: border-box;
+ display: inline;
+ font-size: 10px;
+ font-size: 14px;
+ font-weight: bold;
+ height: 20px;
+ line-height: 20px;
+ margin: 0;
+ overflow: hidden;
+ text-align: center;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+.tasksCalendar[view=month] .wrappers {
+ display: grid;
+ gap: 4px 4px;
+ grid-template-columns: 1fr !important;
+ grid-template-rows: repeat(6, 16.6666666667%);
+ height: calc(100% - 20px);
+ min-height: 0;
+}
+.tasksCalendar[view=month] .wrapper {
+ border-radius: 5px;
+ border: 1px solid var(--nav-item-background-active);
+ display: grid;
+ grid-template-columns: 22px 1fr 1fr 1fr 1fr 1fr 1fr 1fr !important;
+ grid-template-rows: 1fr !important;
+ height: 100%;
+ overflow: hidden;
+ width: 100%;
+ z-index: 1;
+}
+.tasksCalendar[view=month] .wrapperButton {
+ align-items: center;
+ background: none;
+ /* background: $background-primary; */
+ background: var(--background-secondary);
+ color: var(--text-normal);
+ color: var(--icon-color-active);
+ cursor: pointer;
+ display: flex;
+ font-size: 10px;
+ font-weight: normal;
+ justify-content: center;
+ overflow: hidden;
+ text-align: center;
+ transform: rotate(180deg);
+ width: 100%;
+ writing-mode: vertical-lr;
+}
+.tasksCalendar[view=month] .wrapperButton:hover {
+ background: var(--background-modifier-hover);
+}
+.tasksCalendar[view=month] .cell {
+ margin: 0;
+}
+.tasksCalendar[view=month] .cell.today {
+ background: var(--background-modifier-active-hover) !important;
+ border: 1px solid hsla(var(--interactive-accent-hsl), 0.25) !important;
+ border-radius: 5px;
+}
+.tasksCalendar[view=month] .prevMonth,
+.tasksCalendar[view=month] .nextMonth {
+ background: var(--background-secondary);
+}
+.tasksCalendar[view=list] .list {
+ border: 1px solid var(--nav-item-background-active);
+ border-radius: 5px;
+}
+.tasksCalendar[view=list] .list .task .inner {
+ display: flex !important;
+ flex-direction: row;
+ flex-wrap: nowrap;
+ padding: 0 10px;
+ white-space: nowrap;
+}
+.tasksCalendar[view=list] .list .task .note {
+ display: inline-block;
+ flex-grow: 0;
+ flex-shrink: 0;
+ width: 150px;
+}
+.tasksCalendar[view=list] .list .task .description {
+ flex-grow: 1;
+ flex-shrink: 1;
+ width: 100%;
+}
+.tasksCalendar[view=list] .list .task.done .note, .tasksCalendar[view=list] .list .task.done .description, .tasksCalendar[view=list] .list .task.cancelled .note, .tasksCalendar[view=list] .list .task.cancelled .description {
+ color: var(--text-faint) !important;
+}
+.tasksCalendar[view=list] .list .task, .tasksCalendar[view=list] .list .task.done,
+.tasksCalendar[view=list] .list .task .note, .tasksCalendar[view=list] .list .task.done .note {
+ background: transparent !important;
+}
+.tasksCalendar[view=list] .list .task .note,
+.tasksCalendar[view=list] .list .task .description {
+ color: var(--task-color) !important;
+ font-size: 14px;
+ line-clamp: 0 !important;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap !important;
+}
+.tasksCalendar[view=list] details {
+ /*background: $background-secondary;*/
+ border-radius: 5px;
+ border: 1px solid var(--nav-item-background-active);
+ display: block;
+ margin: 5px;
+}
+.tasksCalendar[view=list] details.today {
+ background: var(--background-modifier-active-hover);
+ border: 1px solid hsla(var(--interactive-accent-hsl), 0.25);
+}
+.tasksCalendar[view=list] details.today summary {
+ background: none;
+ font-weight: bold;
+}
+.tasksCalendar[view=list] details.today .content {
+ margin: 3px;
+}
+.tasksCalendar[view=list] summary {
+ background: var(--background-secondary);
+ border-radius: 5px;
+ padding: 0 10px;
+}
+.tasksCalendar[view=list] summary span.weekNr {
+ color: var(--text-faint);
+ font-size: 11px;
+}
+.tasksCalendar[view=list] button.listView, .tasksCalendar[view=week] button.weekView, .tasksCalendar[view=month] button.monthView, .tasksCalendar.filter button.filter {
+ background: var(--background-modifier-active-hover);
+}
+.tasksCalendar[view=list] button.listView svg, .tasksCalendar[view=week] button.weekView svg, .tasksCalendar[view=month] button.monthView svg, .tasksCalendar.filter button.filter svg {
+ stroke: var(--icon-color-active) !important;
+}
+.tasksCalendar[view=month] .wrappers, .tasksCalendar[view=week] .grid {
+ position: relative;
+}
+.tasksCalendar[view=month] .wrappers:before, .tasksCalendar[view=week] .grid:before, .tasksCalendar[view=list] .list:before {
+ color: var(--background-modifier-active-hover);
+ font-size: 120px;
+ font-weight: bold;
+ left: 50%;
+ position: absolute;
+ top: 50%;
+ transform: translate(-50%, -50%);
+ z-index: 0;
+}
+.tasksCalendar[view=month] .wrappers:before, .tasksCalendar[view=list] .list:before {
+ content: attr(data-month);
+}
+.tasksCalendar.focusDailyNote .task {
+ opacity: 0.25 !important;
+}
+.tasksCalendar.focusDailyNote .task.dailyNote {
+ opacity: 1 !important;
+}
+.tasksCalendar.focusDone .task {
+ opacity: 0.25 !important;
+}
+.tasksCalendar.focusDone .task.done {
+ opacity: 1 !important;
+}
+.tasksCalendar.focusDue .task {
+ opacity: 0.25 !important;
+}
+.tasksCalendar.focusDue .task.due {
+ opacity: 1 !important;
+}
+.tasksCalendar.focusOverdue .task {
+ opacity: 0.25 !important;
+}
+.tasksCalendar.focusOverdue .task.overdue {
+ opacity: 1 !important;
+}
+.tasksCalendar.focusRecurrence .task {
+ opacity: 0.25 !important;
+}
+.tasksCalendar.focusRecurrence .task.recurrence {
+ opacity: 1 !important;
+}
+.tasksCalendar.focusScheduled .task {
+ opacity: 0.25 !important;
+}
+.tasksCalendar.focusScheduled .task.scheduled {
+ opacity: 1 !important;
+}
+.tasksCalendar.focusStart .task {
+ opacity: 0.25 !important;
+}
+.tasksCalendar.focusStart .task.start {
+ opacity: 1 !important;
+}
+
+.iconStyle11 {
+ display: none !important;
+}
+
+.tasksCalendar[view=week].style1 .grid,
+.iconStyle1 {
+ grid-template-columns: repeat(4, 1fr);
+ grid-template-rows: repeat(6, 1fr);
+}
+
+.tasksCalendar[view=week].style2 .grid,
+.iconStyle2 {
+ grid-template-columns: repeat(4, 1fr);
+ grid-template-rows: repeat(6, 1fr);
+}
+
+.tasksCalendar[view=week].style3 .grid,
+.iconStyle3 {
+ grid-template-columns: 1fr;
+ grid-template-rows: repeat(7, 1fr);
+}
+
+.tasksCalendar[view=week].style4 .grid,
+.iconStyle4 {
+ grid-template-columns: repeat(7, 1fr);
+ grid-template-rows: 1fr;
+}
+
+.tasksCalendar[view=week].style5 .grid,
+.iconStyle5 {
+ grid-template-columns: repeat(2, 1fr);
+ grid-template-rows: repeat(10, 1fr);
+}
+
+.tasksCalendar[view=week].style6 .grid,
+.iconStyle6 {
+ grid-template-columns: repeat(3, 1fr);
+ grid-template-rows: repeat(10, 1fr);
+}
+
+.tasksCalendar[view=week].style7 .grid,
+.iconStyle7 {
+ grid-template-columns: repeat(2, 1fr);
+ grid-template-rows: repeat(8, 1fr);
+}
+
+.tasksCalendar[view=week].style8 .grid,
+.iconStyle8 {
+ grid-template-columns: repeat(3, 1fr);
+ grid-template-rows: repeat(5, 1fr);
+}
+
+.tasksCalendar[view=week].style9 .grid,
+.iconStyle9 {
+ grid-template-columns: repeat(10, 1fr);
+ grid-template-rows: repeat(3, 1fr);
+}
+
+.tasksCalendar[view=week].style10 .grid,
+.iconStyle10 {
+ grid-template-columns: repeat(10, 1fr);
+ grid-template-rows: repeat(3, 1fr);
+}
+
+.tasksCalendar[view=week].style11 .grid,
+.iconStyle11 {
+ grid-template-columns: repeat(5, 1fr);
+ grid-template-rows: 1fr;
+}
+
+.tasksCalendar[view=week].style1 .grid .cell:nth-child(1),
+.iconStyle1 .box:nth-child(1) {
+ grid-area: 1/1/3/2;
+}
+
+.tasksCalendar[view=week].style1 .grid .cell:nth-child(2),
+.iconStyle1 .box:nth-child(2) {
+ grid-area: 3/1/5/3;
+}
+
+.tasksCalendar[view=week].style1 .grid .cell:nth-child(3),
+.iconStyle1 .box:nth-child(3) {
+ grid-area: 5/1/7/3;
+}
+
+.tasksCalendar[view=week].style1 .grid .cell:nth-child(4),
+.iconStyle1 .box:nth-child(4) {
+ grid-area: 1/3/3/5;
+}
+
+.tasksCalendar[view=week].style1 .grid .cell:nth-child(5),
+.iconStyle1 .box:nth-child(5) {
+ grid-area: 3/3/5/5;
+}
+
+.tasksCalendar[view=week].style1 .grid .cell:nth-child(6),
+.iconStyle1 .box:nth-child(6) {
+ grid-area: 5/3/6/5;
+}
+
+.tasksCalendar[view=week].style1 .grid .cell:nth-child(7),
+.iconStyle1 .box:nth-child(7) {
+ grid-area: 6/3/7/5;
+}
+
+.tasksCalendar[view=week].style2 .grid .cell:nth-child(1),
+.iconStyle2 .box:nth-child(1) {
+ grid-area: 1/1/3/3;
+}
+
+.tasksCalendar[view=week].style2 .grid .cell:nth-child(2),
+.iconStyle2 .box:nth-child(2) {
+ grid-area: 3/1/5/3;
+}
+
+.tasksCalendar[view=week].style2 .grid .cell:nth-child(3),
+.iconStyle2 .box:nth-child(3) {
+ grid-area: 5/1/7/3;
+}
+
+.tasksCalendar[view=week].style2 .grid .cell:nth-child(4),
+.iconStyle2 .box:nth-child(4) {
+ grid-area: 1/3/3/5;
+}
+
+.tasksCalendar[view=week].style2 .grid .cell:nth-child(5),
+.iconStyle2 .box:nth-child(5) {
+ grid-area: 3/3/5/5;
+}
+
+.tasksCalendar[view=week].style2 .grid .cell:nth-child(6),
+.iconStyle2 .box:nth-child(6) {
+ grid-area: 5/3/6/5;
+}
+
+.tasksCalendar[view=week].style2 .grid .cell:nth-child(7),
+.iconStyle2 .box:nth-child(7) {
+ grid-area: 6/3/7/5;
+}
+
+.tasksCalendar[view=week].style5 .grid .cell:nth-child(1),
+.iconStyle5 .box:nth-child(1) {
+ grid-area: 1/1/3/2;
+}
+
+.tasksCalendar[view=week].style5 .grid .cell:nth-child(2),
+.iconStyle5 .box:nth-child(2) {
+ grid-area: 3/1/5/2;
+}
+
+.tasksCalendar[view=week].style5 .grid .cell:nth-child(3),
+.iconStyle5 .box:nth-child(3) {
+ grid-area: 5/1/7/2;
+}
+
+.tasksCalendar[view=week].style5 .grid .cell:nth-child(4),
+.iconStyle5 .box:nth-child(4) {
+ grid-area: 7/1/9/2;
+}
+
+.tasksCalendar[view=week].style5 .grid .cell:nth-child(5),
+.iconStyle5 .box:nth-child(5) {
+ grid-area: 9/1/11/2;
+}
+
+.tasksCalendar[view=week].style5 .grid .cell:nth-child(6),
+.iconStyle5 .box:nth-child(6) {
+ grid-area: 1/2/6/3;
+}
+
+.tasksCalendar[view=week].style5 .grid .cell:nth-child(7),
+.iconStyle5 .box:nth-child(7) {
+ grid-area: 6/2/11/3;
+}
+
+.tasksCalendar[view=week].style6 .grid .cell:nth-child(1),
+.iconStyle6 .box:nth-child(1) {
+ grid-area: 1/1/3/3;
+}
+
+.tasksCalendar[view=week].style6 .grid .cell:nth-child(2),
+.iconStyle6 .box:nth-child(2) {
+ grid-area: 3/1/5/3;
+}
+
+.tasksCalendar[view=week].style6 .grid .cell:nth-child(3),
+.iconStyle6 .box:nth-child(3) {
+ grid-area: 5/1/7/3;
+}
+
+.tasksCalendar[view=week].style6 .grid .cell:nth-child(4),
+.iconStyle6 .box:nth-child(4) {
+ grid-area: 7/1/9/3;
+}
+
+.tasksCalendar[view=week].style6 .grid .cell:nth-child(5),
+.iconStyle6 .box:nth-child(5) {
+ grid-area: 9/1/11/3;
+}
+
+.tasksCalendar[view=week].style6 .grid .cell:nth-child(6),
+.iconStyle6 .box:nth-child(6) {
+ grid-area: 1/3/6/4;
+}
+
+.tasksCalendar[view=week].style6 .grid .cell:nth-child(7),
+.iconStyle6 .box:nth-child(7) {
+ grid-area: 6/3/11/4;
+}
+
+.tasksCalendar[view=week].style7 .grid .cell:nth-child(1),
+.iconStyle7 .box:nth-child(1) {
+ grid-area: 1/1/3/2;
+}
+
+.tasksCalendar[view=week].style7 .grid .cell:nth-child(2),
+.iconStyle7 .box:nth-child(2) {
+ grid-area: 3/1/5/2;
+}
+
+.tasksCalendar[view=week].style7 .grid .cell:nth-child(3),
+.iconStyle7 .box:nth-child(3) {
+ grid-area: 5/1/7/2;
+}
+
+.tasksCalendar[view=week].style7 .grid .cell:nth-child(4),
+.iconStyle7 .box:nth-child(4) {
+ grid-area: 7/1/9/2;
+}
+
+.tasksCalendar[view=week].style7 .grid .cell:nth-child(5),
+.iconStyle7 .box:nth-child(5) {
+ grid-area: 1/2/3/3;
+}
+
+.tasksCalendar[view=week].style7 .grid .cell:nth-child(6),
+.iconStyle7 .box:nth-child(6) {
+ grid-area: 3/2/6/3;
+}
+
+.tasksCalendar[view=week].style7 .grid .cell:nth-child(7),
+.iconStyle7 .box:nth-child(7) {
+ grid-area: 6/2/9/3;
+}
+
+.tasksCalendar[view=week].style8 .grid .cell:nth-child(1),
+.iconStyle8 .box:nth-child(1) {
+ grid-area: 1/1/3/2;
+}
+
+.tasksCalendar[view=week].style8 .grid .cell:nth-child(2),
+.iconStyle8 .box:nth-child(2) {
+ grid-area: 1/2/3/3;
+}
+
+.tasksCalendar[view=week].style8 .grid .cell:nth-child(3),
+.iconStyle8 .box:nth-child(3) {
+ grid-area: 1/3/3/4;
+}
+
+.tasksCalendar[view=week].style8 .grid .cell:nth-child(4),
+.iconStyle8 .box:nth-child(4) {
+ grid-area: 3/1/5/2;
+}
+
+.tasksCalendar[view=week].style8 .grid .cell:nth-child(5),
+.iconStyle8 .box:nth-child(5) {
+ grid-area: 3/2/5/3;
+}
+
+.tasksCalendar[view=week].style8 .grid .cell:nth-child(6),
+.iconStyle8 .box:nth-child(6) {
+ grid-area: 3/3/5/4;
+}
+
+.tasksCalendar[view=week].style8 .grid .cell:nth-child(7),
+.iconStyle8 .box:nth-child(7) {
+ grid-area: 5/1/6/4;
+}
+
+.tasksCalendar[view=week].style9 .grid .cell:nth-child(1),
+.iconStyle9 .box:nth-child(1) {
+ grid-area: 1/1/3/3;
+}
+
+.tasksCalendar[view=week].style9 .grid .cell:nth-child(2),
+.iconStyle9 .box:nth-child(2) {
+ grid-area: 1/3/3/5;
+}
+
+.tasksCalendar[view=week].style9 .grid .cell:nth-child(3),
+.iconStyle9 .box:nth-child(3) {
+ grid-area: 1/5/3/7;
+}
+
+.tasksCalendar[view=week].style9 .grid .cell:nth-child(4),
+.iconStyle9 .box:nth-child(4) {
+ grid-area: 1/7/3/9;
+}
+
+.tasksCalendar[view=week].style9 .grid .cell:nth-child(5),
+.iconStyle9 .box:nth-child(5) {
+ grid-area: 1/9/3/11;
+}
+
+.tasksCalendar[view=week].style9 .grid .cell:nth-child(6),
+.iconStyle9 .box:nth-child(6) {
+ grid-area: 3/1/4/6;
+}
+
+.tasksCalendar[view=week].style9 .grid .cell:nth-child(7),
+.iconStyle9 .box:nth-child(7) {
+ grid-area: 3/6/4/11;
+}
+
+.tasksCalendar[view=week].style10 .grid .cell:nth-child(1),
+.iconStyle10 .box:nth-child(1) {
+ grid-area: 1/1/4/3;
+}
+
+.tasksCalendar[view=week].style10 .grid .cell:nth-child(2),
+.iconStyle10 .box:nth-child(2) {
+ grid-area: 1/3/4/5;
+}
+
+.tasksCalendar[view=week].style10 .grid .cell:nth-child(3),
+.iconStyle10 .box:nth-child(3) {
+ grid-area: 1/5/4/7;
+}
+
+.tasksCalendar[view=week].style10 .grid .cell:nth-child(4),
+.iconStyle10 .box:nth-child(4) {
+ grid-area: 1/7/3/9;
+}
+
+.tasksCalendar[view=week].style10 .grid .cell:nth-child(5),
+.iconStyle10 .box:nth-child(5) {
+ grid-area: 1/9/3/11;
+}
+
+.tasksCalendar[view=week].style10 .grid .cell:nth-child(6),
+.iconStyle10 .box:nth-child(6) {
+ grid-area: 3/7/4/9;
+}
+
+.tasksCalendar[view=week].style10 .grid .cell:nth-child(7),
+.iconStyle10 .box:nth-child(7) {
+ grid-area: 3/9/4/11;
+}
+
+body:not(.is-mobile) .tasksCalendar button.listView:hover,
+body:not(.is-mobile) .tasksCalendar button.weekView:hover,
+body:not(.is-mobile) .tasksCalendar button.monthView:hover,
+body:not(.is-mobile) .tasksCalendar button.previous:hover,
+body:not(.is-mobile) .tasksCalendar button.next:hover,
+body:not(.is-mobile) .tasksCalendar button.current:hover,
+body:not(.is-mobile) .tasksCalendar button.filter:hover,
+body:not(.is-mobile) .tasksCalendar button.statistic:hover {
+ background: var(--background-modifier-hover);
+}
+body:not(.is-mobile) .tasksCalendar .statisticPopup li:not(.active):hover,
+body:not(.is-mobile) .tasksCalendar .weekViewContext li:not(.active):hover {
+ background: var(--background-modifier-hover);
+}
+body:not(.is-mobile) .tasksCalendar .cellName:hover {
+ opacity: 1;
+}
+body:not(.is-mobile) .tasksCalendar .task:hover {
+ opacity: 1;
+}
+body.theme-dark .tasksCalendar .task {
+ color: var(--light-task-text-color);
+}
+body.theme-dark .tasksCalendar .task .note {
+ color: var(--light-task-text-color);
+}
+body.theme-light .tasksCalendar .task {
+ color: var(--dark-task-text-color);
+}
+body.theme-light .tasksCalendar .task .note {
+ color: var(--dark-task-text-color);
+}
+body.is-mobile .tasksCalendar .gridHead,
+body.is-mobile .tasksCalendar .cellName,
+body.is-mobile .tasksCalendar .task {
+ font-size: 9px;
+}
+body.is-mobile .tasksCalendar[view=week]:not(.style4) .cellName, body.is-mobile .tasksCalendar[view=week]:not(.style4) .task {
+ font-size: 13px !important;
+}
+body.is-mobile .tasksCalendar .statisticPopup li {
+ font-size: 13px !important;
+}
+
+.taskido {
+ cursor: default;
+ user-select: none;
+}
+.taskido .task {
+ border-radius: 10px;
+ cursor: pointer;
+ display: flex;
+ flex-direction: row;
+ flex-wrap: nowrap;
+ margin: 0;
+ padding: 0;
+}
+.taskido .task.overdue .timeline .icon svg line {
+ stroke-width: 2.5px !important;
+ stroke: #ff375f !important;
+}
+.taskido .task.overdue .info .relative {
+ color: #ff375f !important;
+}
+.taskido .task.done .timeline .icon svg {
+ fill: var(--interactive-accent) !important;
+ stroke: var(--interactive-accent) !important;
+}
+.taskido .task.done .timeline .icon svg path:nth-child(1) {
+ fill: var(--interactive-accent) !important;
+}
+.taskido .task.done .timeline .icon svg path:nth-child(2) {
+ stroke-width: 2.5px;
+ stroke: var(--checkbox-marker-color) !important;
+}
+.taskido .task .content {
+ color: var(--text-normal);
+ display: block;
+ font-size: 15px;
+ font-weight: normal;
+ line-height: 22px;
+ white-space: break-word;
+}
+.taskido .task .info {
+ cursor: default;
+ line-height: 22px;
+ padding-bottom: 2px;
+}
+.taskido .task .info:empty {
+ display: none;
+}
+.taskido .task .info .file {
+ color: var(--task-color);
+}
+.taskido .task .info .tag {
+ background: none !important;
+ color: var(--tag-color) !important;
+ cursor: pointer;
+}
+.taskido .task .info .icon {
+ height: 15px;
+ text-align: center;
+}
+.taskido .task .info .label {
+ margin-left: 2px;
+}
+.taskido .task .info svg {
+ height: 12px;
+ stroke-width: 1.75px;
+ width: 12px;
+}
+.taskido .task .info .tag,
+.taskido .task .info .repeat,
+.taskido .task .info .priority,
+.taskido .task .info .relative,
+.taskido .task .info .file {
+ align-items: center;
+ border-radius: 3px !important;
+ border: none;
+ color: var(--text-muted);
+ display: flex;
+ flex-direction: row;
+ flex-wrap: nowrap;
+ font-size: 9px;
+ font-weight: normal;
+ line-height: 1 !important;
+ margin: 2px 5px 2px 0;
+ padding: 0;
+ padding: 0px;
+ width: auto;
+}
+.taskido .task.done .info .tag,
+.taskido .task.done .info .repeat,
+.taskido .task.done .info .priority,
+.taskido .task.done .info .relative,
+.taskido .task.done .info .file, .taskido .task.cancelled .info .tag,
+.taskido .task.cancelled .info .repeat,
+.taskido .task.cancelled .info .priority,
+.taskido .task.cancelled .info .relative,
+.taskido .task.cancelled .info .file {
+ color: var(--text-muted) !important;
+ line-height: 0;
+}
+.taskido .task.done .content, .taskido .task.cancelled .content {
+ color: var(--text-muted);
+ text-decoration: line-through;
+}
+.taskido .task .innerLink,
+.taskido .task .outerLink {
+ color: var(--interactive-accent);
+ text-decoration: underline !important;
+}
+.taskido .info .icon {
+ text-align: center;
+ height: 15px;
+}
+.taskido .info .label {
+ margin-left: 2px;
+}
+.taskido .info svg {
+ height: 12px;
+ width: 12px;
+ stroke-width: 1.75px;
+}
+.taskido .year {
+ color: var(--text-normal);
+ font-size: 30px;
+ font-weight: bold;
+ margin: 20px 0;
+ text-align: center;
+}
+.taskido .details {
+ display: flex;
+ flex-direction: column;
+ flex-wrap: nowrap;
+ height: auto;
+ width: 100%;
+}
+.taskido .details .today {
+ padding: 30px 0;
+}
+.taskido .todayFocus .todayHeader {
+ color: var(--interactive-accent);
+}
+.taskido .todayFocus .details:not(.today),
+.taskido .todayFocus .year {
+ display: none !important;
+}
+.taskido .todayFocus .details.today {
+ padding: 0;
+}
+.taskido .todayHeader {
+ border-radius: 10px;
+ cursor: pointer;
+ font-size: 24px;
+ font-weight: bold;
+ margin: 10px 5px;
+ text-align: center;
+}
+.taskido .counters {
+ align-content: center;
+ display: flex;
+ flex-direction: row;
+ flex-wrap: nowrap;
+ justify-content: center;
+ margin: 20px 0;
+}
+.taskido .counter {
+ background: var(--interactive-normal);
+ border-radius: 10px;
+ box-shadow: var(--input-shadow);
+ color: var(--text-normal);
+ cursor: pointer;
+ display: flex;
+ flex-direction: column;
+ flex-wrap: nowrap;
+ flex: 1 1 0;
+ margin: 0 5px;
+ max-width: 150px;
+ min-width: 70px;
+ overflow: hidden;
+ padding: 5px;
+ text-align: center;
+}
+.taskido .counter .label {
+ font-size: 12px;
+ font-weight: normal;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+.taskido .count {
+ font-size: 18px;
+ font-weight: normal;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+.taskido .dateLine {
+ align-items: center;
+ display: flex;
+ flex-direction: row;
+ flex-wrap: nowrap;
+ justify-content: space-between;
+ margin: 10px 0;
+}
+.taskido .date {
+ color: var(--text-normal);
+ font-size: 16px;
+ font-weight: bold;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+.taskido .weekday {
+ color: var(--text-normal);
+ font-size: 16px;
+ font-weight: normal;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+.taskido .timeline {
+ flex-grow: 0;
+ flex-shrink: 0;
+ width: 50px;
+}
+.taskido .timeline .icon {
+ height: 22px;
+ text-align: center;
+}
+.taskido .timeline .icon svg {
+ color: var(--checkbox-border-color);
+ height: var(--checkbox-size);
+ stroke-width: 1.75px;
+ width: var(--checkbox-size);
+}
+.taskido .timeline .icon svg:hover {
+ color: var(--checkbox-border-color-hover);
+}
+.taskido .lines {
+ flex-grow: 1;
+ flex-shrink: 1;
+ overflow: hidden;
+}
+.taskido .line {
+ align-items: center;
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+}
+.taskido .stripe {
+ align-items: center;
+ background: var(--checkbox-border-color);
+ display: flex;
+ flex-grow: 1;
+ flex-shrink: 1;
+ justify-content: center;
+ margin: 0 auto;
+ width: 1px;
+}
+.taskido .icon {
+ align-items: center;
+ display: flex;
+ flex-grow: 0;
+ flex-shrink: 0;
+ justify-content: center;
+ text-align: center;
+}
+.taskido .quickEntryPanel {
+ background: var(--background-modifier-form-field);
+ border-radius: 10px;
+ border: var(--input-border-width) solid var(--background-modifier-border);
+ box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.1);
+ color: var(--text-normal);
+ display: flex;
+ flex-direction: row;
+ flex-wrap: nowrap;
+ margin: 0 5px 20px 5px;
+ overflow: hidden;
+ padding: 5px;
+}
+.taskido .quickEntryPanel .left {
+ align-items: center;
+ border-radius: 5px;
+ display: flex;
+ flex-direction: column;
+ flex-grow: 1;
+ flex-shrink: 1;
+ flex-wrap: nowrap;
+ overflow: hidden;
+ padding: 0 5px !important;
+ width: 100%;
+}
+.taskido .quickEntryPanel .right {
+ border-radius: 5px;
+ display: block;
+ flex-grow: 1;
+ flex-shrink: 1;
+ overflow: hidden;
+ width: auto;
+}
+.taskido .quickEntryPanel input {
+ cursor: text;
+ font-size: 14px;
+ height: 20px;
+ line-height: 20px;
+ margin: 0 !important;
+ overflow: hidden;
+ padding: 0 !important;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ width: 100%;
+}
+.taskido .quickEntryPanel select {
+ color: var(--text-muted);
+ font-size: 11px;
+ height: 15px;
+ margin: 2.5px 0 !important;
+ overflow: hidden;
+ padding: 0 !important;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ width: 100%;
+}
+.taskido .quickEntryPanel select option,
+.taskido .quickEntryPanel select optgroup {
+ background: var(--background-primary);
+ color: var(--text-normal);
+ font-weight: normal;
+}
+.taskido .quickEntryPanel button {
+ align-items: center;
+ color: var(--text-muted);
+ display: flex;
+ flex-direction: row;
+ flex-wrap: nowrap;
+ height: 100%;
+ justify-content: center;
+ margin: 0 !important;
+ padding: 0 5px !important;
+ width: auto;
+}
+.taskido .quickEntryPanel svg {
+ height: 15px;
+ stroke-width: 1.75px;
+ width: 15px;
+}
+.taskido .quickEntryPanel select,
+.taskido .quickEntryPanel input,
+.taskido .quickEntryPanel button {
+ background: none !important;
+ border-radius: 0 !important;
+ border: none !important;
+ box-shadow: none !important;
+}
+.taskido .quickEntryPanel select:active,
+.taskido .quickEntryPanel input:active,
+.taskido .quickEntryPanel button:active {
+ border: none !important;
+ box-shadow: none !important;
+ transition: none !important;
+}
+.taskido .quickEntryPanel select,
+.taskido .quickEntryPanel button {
+ cursor: pointer;
+}
+.taskido .quickEntryPanel select:hover,
+.taskido .quickEntryPanel button:hover {
+ color: var(--text-normal);
+}
+.taskido .noColor .task .file {
+ color: var(--text-muted) !important;
+}
+.taskido .noColor .task .info .file {
+ color: var(--text-muted) !important;
+}
+.taskido a {
+ color: inherit !important;
+ text-decoration: none !important;
+}
+.taskido span {
+ display: contents;
+}
+.taskido .timeline,
+.taskido .lines {
+ cursor: default;
+ display: flex;
+ flex-direction: column;
+ flex-wrap: nowrap;
+}
+.taskido .todoFocus .counter#todo,
+.taskido .todoFilter .counter#todo,
+.taskido .overdueFocus .counter#overdue,
+.taskido .overdueFilter .counter#overdue,
+.taskido .unplannedFocus .counter#unplanned,
+.taskido .unplannedFilter .counter#unplanned {
+ background: hsla(var(--interactive-accent-hsl), 0.2);
+ box-shadow: var(--input-shadow);
+ color: var(--interactive-accent);
+}
+.taskido .noYear .year,
+.taskido .noRepeat .repeat,
+.taskido .noTag .tag,
+.taskido .noPriority .priority,
+.taskido .noFile .task .file,
+.taskido .noHeader .task .header,
+.taskido .noFile .task .info > .file,
+.taskido .noInfo .task .line:nth-child(2),
+.taskido .noDone .year[data-types=done],
+.taskido .noDone .details[data-types=done],
+.taskido .noDone .task.done,
+.taskido .noUnplanned .task.unplanned,
+.taskido .noUnplanned .counter#unplanned,
+.taskido .noUnplanned .year[data-types=unplanned],
+.taskido .noUnplanned .details[data-types=unplanned],
+.taskido .noRelative .relative,
+.taskido .noQuickEntry .quickEntryPanel,
+.taskido .noCounters .counters {
+ display: none !important;
+}
+.taskido .todoFocus .details.today .task.due,
+.taskido .todoFocus .details.today .task.scheduled,
+.taskido .todoFocus .details.today .task.process,
+.taskido .todoFocus .details.today .task.start,
+.taskido .overdueFocus .task.overdue,
+.taskido .unplannedFocus .task.unplanned {
+ background: hsla(var(--interactive-accent-hsl), 0.2);
+}
+.taskido .todoFilter .year:not(.current):not([data-types*=due][data-types*=scheduled][data-types*=overdue]),
+.taskido .todoFilter .details:not(.today):not([data-types*=due][data-types*=scheduled][data-types*=overdue]),
+.taskido .todoFilter .task:not(.due, .scheduled, .process, .start),
+.taskido .overdueFilter .year:not(.current):not([data-types*=overdue]),
+.taskido .overdueFilter .details:not(.today):not([data-types*=overdue]),
+.taskido .overdueFilter .task:not(.overdue),
+.taskido .unplannedFilter .year:not(.current):not([data-types*=unplanned]),
+.taskido .unplannedFilter .details:not(.today):not([data-types*=unplanned]),
+.taskido .unplannedFilter .task:not(.unplanned) {
+ display: none;
+}
+
+/*# sourceMappingURL=styles.css.map */
diff --git a/tasksCalendar/README.md b/tasksCalendar/README.md
new file mode 100644
index 0000000..815f395
--- /dev/null
+++ b/tasksCalendar/README.md
@@ -0,0 +1,219 @@
+# Taskido: Obsidian-Tasks-Timeline
+## [Click here!](https://github.com/702573N/Obsidian-Tasks-Timeline)
+
+
+
+---
+
+# Obsidian-Tasks-Calendar
+#### A custom view build with [Obsidian-Dataview](https://github.com/blacksmithgu/obsidian-dataview) to display tasks from [Obsidian-Tasks](https://github.com/obsidian-tasks-group/obsidian-tasks) and from your daily notes in a highly customisable calendar with a wide variety of views
+
+![light](https://user-images.githubusercontent.com/59178587/203789595-ede6138f-2c29-4148-b52f-874ab3ea43f7.png)
+
+## Story
+All Obsidian and Task Plugin users love the program. What has been set up with the Task Plugin is just great and helps so many people to organize their work. However, just listing tasks according to certain criteria is sometimes a bit boring. To get a quick visual impression of one's workday/workweek/workmonth, a calendar view would be ideal. To be honest, I'm too stupid to program my own plugins for Obsidian, but I know some Javascript, so I programmed this Dataview snippet. I hope to offer many people a good addition to the Task Plugin and hope for an integration into the Task Plugin someday. But I'm sure there are better programmers out there, who can make my code, which is probably horrible for professionals, much better.
+
+## Setup
+1. Install "Dataview Plugin" from the external plugins
+2. Create a new folder called "tasksCalendar" or any other name and paste the files "view.js" and "view.css" into it
+
+![Tree Demo](https://user-images.githubusercontent.com/59178587/203789303-4474847e-ab84-4f33-8665-c17ca887ec79.png)
+
+3. Create a new note or edit an existing one and add the following code line:
+
+ ````
+ ```dataviewjs
+ await dv.view("tasksCalendar", {pages: "", view: "month", firstDayOfWeek: "1", options: "style1"})
+ ```
+ ````
+
+ If you paste the main files (js/css) into another folder then "tasksCalendar", you have to replace the name between the first quotation marks.
+
+ 4. There are 4 different variables to set path/location as "pages", calendar view style as "view", first day of the week (0 or 1) as "firstDayOfWeek" and some style classes as "options"
+
+---
+## Required parameters
+
+### pages:
+
+For help and instruction take a look here [Dataview Help](https://blacksmithgu.github.io/obsidian-dataview/api/code-reference/#dvpagessource)
+
+```
+pages: ""
+```
+Get all tasks from all notes in obsidian.
+
+```
+pages: '"Task Management/Work"'
+```
+Set a custom folder to get tasks from.
+
+The dv.pages command is the same and works exactly the same like in dataview-plugin.
+
+```
+pages: "dv.pages().file.tasks.where(t => t.tags.includes('#Pierre'))"
+pages: "dv.pages().file.tasks.where(t=>!t.checked && t.header.subpath != 'Log')"
+pages: "dv.pages().file.where(f=>f.tags.includes('#ToDo') || f.tags.includes('#Task')).where(f=>f.folder != 'Inbox').tasks"
+```
+It is also possible to define complex queries. These must start with `dv.pages` and output tasks as a result.
+
+
+### view:
+```
+view: "list"
+view: "month"
+view: "week"
+```
+With the view parameter you can set the default calendar view.
+
+
+### firstDayOfWeek:
+```
+firstDayOfWeek: "1"
+firstDayOfWeek: "0"
+```
+Set monday (1) or sunday (0) as first day of week
+
+
+### options:
+```
+options: "style1"
+```
+You have multiple options to personalize your Tasks-Calendar. The absolutelely must have is to set a custom week view style (style1, style2, ...) as your default week view style. However, you can switch between the individual styles at any time in the calendar itself by clicking the week view button again if this view is active.
+
+
+
+But that's not all. With the options parameter you can hide things you don't need or like, get a mini version of the calendar and many more...
+
+```
+options: "noIcons"
+```
+Hide the task icons in front of each task.
+
+```
+options: "noProcess"
+```
+By default the Tasks-Calendar show up tasks with a start- and a due-date on all days between these two like a calendar app displays all-day events across all days from the first to the last day. If you don't like this, you can turn it off with the `noProcess` option.
+
+```
+options: "noDailyNote"
+```
+Hide daily notes inside calendar
+
+Some users do not use the Task plugin, but work mainly with daily notes. To enable these users to use the functionality of this calendar, all tasks from daily notes are displayed on the respective date of the daily note. As some task plugin users may also work with daily notes, some may find it annoying to see them in the calendar as well between all Task plugin stuff. With the option `noDailyNote` you can hide all tasks (without any Task plugin date syntax) from your calendar.
+
+```
+options: "noCellNameEvent"
+```
+By default you can click on each cell name to jump directly into the daily note. If no daily note with this date exist, a new one will be created. This is nice for hardcore daily note users, but for others it could be annoying. To prevent unintentional execution you can disable the cell name click-events with the option `noCellNameEvent`.
+
+```
+options: "mini"
+```
+Reduces the calendar width, height and font sizes to a more compact format. This can be used to embed the calendar into a complex sidebar in Obsidian.
+On mobile devices, the font size is automatically reduced (on some views) because the limited screen size.
+
+```
+options: "noWeekNr"
+```
+Hide the week number in front of each week-wrapper inside the month calendar. After deactivation, it is unfortunately no longer possible to jump directly to a desired week.
+
+```
+options: "noFilename"
+```
+Hides the task header line with the note file name
+
+```
+options: "lineClamp1"
+options: "lineClamp2"
+options: "lineClamp3"
+options: "noLineClamp"
+```
+Set a line clamp from 1-3 inside your displayed tasks. By default 1 line is set. Alternative you can disable line clamp and show full task description text.
+
+```
+options: "noLayer"
+```
+The back layer of the grid with the month or week information can be hidden with this.
+
+```
+options: "noOverdueDays"
+```
+You can use this option to hide the overdue days flag on overdue tasks.
+
+### Optional parameters
+
+#### dailyNoteFolder:
+```
+dailyNoteFolder: "MyCustomFolder"
+dailyNoteFolder: "Inbox/Daily Notes/Work"
+```
+This parameter must only be specified if this is to be used. Here you can define a custom folder path for the daily notes if they should not be saved in the default folder for new files. Of course, folder structures with several levels can also be defined here. This paramter
+
+#### dailyNoteFormat:
+```
+dailyNoteFormat: "YYYY, MMMM DD - dddd"
+dailyNoteFormat: "YYYY-[W]ww"
+```
+This parameter must only be specified if this is to be used. Without this parameter the default format "YYYY-MM-DD" is used to identify your daily notes. You can set a custom format with a limited base set of characters: Y M D [W] ww d . , - : (SPACE)
+
+#### startPosition:
+
+Month: 2022 - December
+```
+view: "month"
+startPosition: "2022-12"
+```
+
+Week: 2022 - W50
+```
+view: "week"
+startPosition: "2022-50"
+```
+This parameter is optional and can be used to set a custom month or week to give focus after load. The default format on month view is `YYYY-MM`and on week view `YYYY-ww`. The first 4 digits represents the year and the last 1-2 digits represents the month or the week. Both must be separated with a minus character.
+
+#### globalTaskFilter:
+```
+globalTaskFilter: "#task"
+```
+This parameter must only be specified if this is to be used. Set a global task filter to hide from task text/description inside tasks-calendar.
+
+#### css:
+```
+css: ".tasksCalendar.style4[view='week'] .grid { height: 300px !important }"
+```
+Now you can write custom css rules inside a css parameter. Please use the developer console to identify the elements classes! Each style string should start with .tasksCalendar to avoid css conflicts!
+
+---
+
+## Note colors and icon
+In each note file you can define custom "color" and "icon" to show up in the calendar. To do so, you only need to add the following metadata to the first line of your note. By default the note-color is used for the dimmed background and as text-color. If you would like to give your tasks a completely different color then the note-color itself, then use the textColor meta.
+
+```
+---
+color: "#bf5af2"
+textColor: "#000000"
+icon: "❤️"
+---
+```
+
+The color should be hex in quotation marks to work properly. This color is set for text and as semi-transparent background. The icon itself is placed in front of the task filename header.
+
+![Note Color Demo](https://user-images.githubusercontent.com/59178587/203788233-555edbc4-915c-499c-bdf4-87c6030bfd55.png)
+
+---
+
+## Filter
+On the upper left corner of each calendar-view is a filter-icon to show or hide all done and cancelled tasks. The default-filter is set by options. If you have `filter` inside your options parameter, the filter is enabled by default.
+
+![Filter Demo](https://user-images.githubusercontent.com/59178587/203787018-483bf485-3ce5-43b4-99ae-2a3a8efbf690.png)
+
+---
+
+## Statistic and focus
+
+On the upper right corner is statistic button which opens a detailed list of all your tasks for the currently selected month/week. By selecting a task type you can focusing this tasks and dimm out all others. This way you can find the tasks you are looking for more easily.
+
+Through a meaningful icon and a counter, you can quickly get an overview of incompleted tasks within the selected month/week without opening the pop-up window.
+
+![Focus Demo](https://user-images.githubusercontent.com/59178587/203786131-6ddf1389-8b66-4f3c-9d7a-121c5fe38540.png)
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..37c360d
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,25 @@
+{
+ "compilerOptions": {
+ "baseUrl": ".",
+ "inlineSourceMap": true,
+ "inlineSources": true,
+ "module": "ESNext",
+ "target": "ES6",
+ "allowJs": true,
+ "noImplicitAny": true,
+ "moduleResolution": "node",
+ "importHelpers": true,
+ "isolatedModules": true,
+ "strictNullChecks": true,
+ "lib": [
+ "DOM",
+ "ES5",
+ "ES6",
+ "ES7",
+ "es2021",
+ ]
+ },
+ "include": [
+ "**/*.ts"
+ ]
+}
diff --git a/version-bump.mjs b/version-bump.mjs
new file mode 100644
index 0000000..d409fa0
--- /dev/null
+++ b/version-bump.mjs
@@ -0,0 +1,14 @@
+import { readFileSync, writeFileSync } from "fs";
+
+const targetVersion = process.env.npm_package_version;
+
+// read minAppVersion from manifest.json and bump version to target version
+let manifest = JSON.parse(readFileSync("manifest.json", "utf8"));
+const { minAppVersion } = manifest;
+manifest.version = targetVersion;
+writeFileSync("manifest.json", JSON.stringify(manifest, null, "\t"));
+
+// update versions.json with target version and minAppVersion from manifest.json
+let versions = JSON.parse(readFileSync("versions.json", "utf8"));
+versions[targetVersion] = minAppVersion;
+writeFileSync("versions.json", JSON.stringify(versions, null, "\t"));
diff --git a/versions.json b/versions.json
new file mode 100644
index 0000000..26382a1
--- /dev/null
+++ b/versions.json
@@ -0,0 +1,3 @@
+{
+ "1.0.0": "0.15.0"
+}