diff --git a/docs/images/personal_tasks.png b/docs/images/personal_tasks.png
new file mode 100644
index 0000000..88777db
Binary files /dev/null and b/docs/images/personal_tasks.png differ
diff --git a/docs/index.md b/docs/index.md
index cc31eef..446fc0a 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -94,6 +94,20 @@ Here, you can see your current tasks and how many problems you need to solve to
+### Personal tasks
+
+You can add your personal tasks:
+
+````
+```euler-stats
+Solve problem 3; 0%
+Solve problem 14; 15.6%
+Solve problem 15; 27.1%
+```
+````
+
+
+
### Location progress
This section provides an overview of your ranking in the **Location rating** on Project Euler.
diff --git a/helpers/fetchProgress.ts b/helpers/fetchProgress.ts
index 9ceb943..b29479b 100644
--- a/helpers/fetchProgress.ts
+++ b/helpers/fetchProgress.ts
@@ -18,9 +18,11 @@ import {
AccountData,
AwardBlockData,
FriendData,
+ LevelData,
+ PersonalTask,
ProgressData,
RatingData,
- LevelData
+ Source
} from './types';
const mainUrl = 'https://projecteuler.net/';
@@ -34,11 +36,11 @@ const keepAliveName = 'keep_alive';
* @param retries - The number of retries in case of failure.
* @returns A Promise that resolves to an HTMLElement.
*/
-export async function fetchProgress(session: string, keep_alive: string): Promise {
+export async function fetchProgress(session: string, keep_alive: string, source: Source): Promise {
const cookies = `${sessionIdName}=${session}; ${keepAliveName}=${keep_alive}`;
try {
- return await tryToFetchProgress(cookies);
+ return await tryToFetchProgress(cookies, source);
} catch (error) {
console.error('Error fetching progress:', error);
@@ -48,7 +50,7 @@ export async function fetchProgress(session: string, keep_alive: string): Promis
}
}
-async function tryToFetchProgress(cookies: string): Promise {
+async function tryToFetchProgress(cookies: string, source: Source): Promise {
const [
accountData,
progressData,
@@ -78,7 +80,8 @@ async function tryToFetchProgress(cookies: string): Promise {
languageRating,
levelDataArray,
awardsData,
- friends
+ friends,
+ source
);
}
@@ -119,7 +122,8 @@ function generateHTML(
languageRating: RatingData,
levelDataArray: LevelData[],
awardsData: AwardBlockData[],
- friends: FriendData[]
+ friends: FriendData[],
+ source: Source
): HTMLElement {
const container = document.createElement('div');
@@ -129,7 +133,7 @@ function generateHTML(
const imageElement = generateImageHTML(accountData.account);
container.appendChild(imageElement);
- const progressElement = generateProgressTableHTML(accountData, progressData, locationUrl, languageUrl, euleriansPlace, locationRating, languageRating, awardsData);
+ const progressElement = generateProgressTableHTML(accountData, progressData, locationUrl, languageUrl, euleriansPlace, locationRating, languageRating, awardsData, source);
container.appendChild(progressElement);
const locationRatingElement = generateRatingTableHTML(locationUrl, accountData.location, progressData.solved, locationRating);
diff --git a/helpers/parsers.ts b/helpers/parsers.ts
index 5d87955..864da68 100644
--- a/helpers/parsers.ts
+++ b/helpers/parsers.ts
@@ -12,7 +12,7 @@ export function extractSolvedCount(text: string): number {
return match && match[1] ? parseInt(match[1], 10) : 0;
}
-function extractPercentage(input: string): number {
+export function extractPercentage(input: string): number {
const regex = /(\d+(\.\d+)?)%/;
const match = input.match(regex);
diff --git a/helpers/progressBlock.ts b/helpers/progressBlock.ts
index ed00e55..dd4312b 100644
--- a/helpers/progressBlock.ts
+++ b/helpers/progressBlock.ts
@@ -1,4 +1,4 @@
-import { AccountData, AwardData, AwardBlockData, ProgressData, RatingData } from './types';
+import { AccountData, AwardData, AwardBlockData, PersonalTask, ProgressData, RatingData, Source } from './types';
import { createProgressBar, createSectionHeader } from './commonBlocks';
interface Result {
@@ -140,6 +140,20 @@ function createProgressTable(
return table;
}
+function createPersonalTasksList(personalTasks: PersonalTask[]): HTMLElement {
+ const tasksList = document.createElement('ul');
+ tasksList.className = 'tasks-list';
+
+ personalTasks.forEach(personalTask => {
+ const li = document.createElement('li');
+ li.textContent = personalTask.task;
+ li.appendChild(createProgressBar(personalTask.percentage));
+ tasksList.appendChild(li);
+ });
+
+ return tasksList;
+}
+
function createTasksList(
progressData: ProgressData,
accountData: AccountData,
@@ -200,6 +214,7 @@ function createTasksList(
* @param locationRating - The location rating data.
* @param languageRating - The language rating data.
* @param awardsData - The awards data.
+ * @param source - The source data.
* @returns The generated HTMLElement (progress table container).
*/
export function generateProgressTableHTML(
@@ -210,7 +225,8 @@ export function generateProgressTableHTML(
euleriansPlace: string,
locationRating: RatingData,
languageRating: RatingData,
- awardsData: AwardBlockData[]
+ awardsData: AwardBlockData[],
+ source: Source
): HTMLElement {
const progressContainer = document.createElement('div');
progressContainer.appendChild(createSectionHeader('Progress'));
@@ -225,6 +241,12 @@ export function generateProgressTableHTML(
languageRating
));
+ // Personal tasks section
+ const personalTasksHeader = document.createElement('h3');
+ personalTasksHeader.textContent = 'Personal tasks';
+ progressContainer.appendChild(personalTasksHeader);
+ progressContainer.appendChild(createPersonalTasksList(source.tasks));
+
// Tasks section
const tasksHeader = document.createElement('h3');
tasksHeader.textContent = 'Tasks';
diff --git a/helpers/sourceExtractor.ts b/helpers/sourceExtractor.ts
new file mode 100644
index 0000000..5d01e03
--- /dev/null
+++ b/helpers/sourceExtractor.ts
@@ -0,0 +1,14 @@
+import { Source, PersonalTask } from './types';
+import { extractPercentage } from './parsers';
+
+export function extractSources(source: string): Source {
+ const tasks = source
+ .split('\n')
+ .filter(line => line.trim() !== '')
+ .map(line => {
+ const [task, percentage] = line.split(';').map(part => part.trim());
+ return new PersonalTask(task, extractPercentage(percentage));
+ });
+
+ return new Source(tasks);
+}
diff --git a/helpers/types.ts b/helpers/types.ts
index 3bcd13a..6ceb73e 100644
--- a/helpers/types.ts
+++ b/helpers/types.ts
@@ -110,3 +110,16 @@ export class FriendData {
public awards: number
) {}
}
+
+export class Source {
+ constructor(
+ public tasks: PersonalTask[],
+ ) {}
+}
+
+export class PersonalTask {
+ constructor(
+ public task: string,
+ public percentage: number
+ ) {}
+}
diff --git a/main.ts b/main.ts
index 4858748..081297a 100644
--- a/main.ts
+++ b/main.ts
@@ -1,5 +1,6 @@
import { App, Editor, MarkdownView, Modal, Notice, Plugin, PluginSettingTab, Setting } from 'obsidian';
import { fetchProgress } from "helpers/fetchProgress";
+import { extractSources } from "helpers/sourceExtractor";
export default class ProjectEulerStatsPlugin extends Plugin {
settings: ProjectEulerStatsSettings;
@@ -13,7 +14,8 @@ export default class ProjectEulerStatsPlugin extends Plugin {
const keep_alive = this.settings.keep_alive;
this.registerMarkdownCodeBlockProcessor('euler-stats', async (source, el, ctx) => {
- const stats = await fetchProgress(session, keep_alive);
+ const extractedSource = extractSources(source);
+ const stats = await fetchProgress(session, keep_alive, extractedSource);
const container = el.createEl('div');
container.appendChild(stats);
});