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 tasks +### Personal tasks + +You can add your personal tasks: + +```` +```euler-stats +Solve problem 3; 0% +Solve problem 14; 15.6% +Solve problem 15; 27.1% +``` +```` + +personal tasks + ### 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); });