Add personal tasks

This commit is contained in:
Artem Korsakov 2025-03-22 09:50:58 +03:00
parent 2de9245e28
commit dc3d0ab277
8 changed files with 80 additions and 11 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

View file

@ -94,6 +94,20 @@ Here, you can see your current tasks and how many problems you need to solve to
<img src="images/tasks.png" alt="tasks" width="500" />
### Personal tasks
You can add your personal tasks:
````
```euler-stats
Solve problem 3; 0%
Solve problem 14; 15.6%
Solve problem 15; 27.1%
```
````
<img src="images/personal_tasks.png" alt="personal tasks" width="500" />
### Location progress
This section provides an overview of your ranking in the **Location rating** on Project Euler.

View file

@ -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<HTMLElement> {
export async function fetchProgress(session: string, keep_alive: string, source: Source): Promise<HTMLElement> {
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<HTMLElement> {
async function tryToFetchProgress(cookies: string, source: Source): Promise<HTMLElement> {
const [
accountData,
progressData,
@ -78,7 +80,8 @@ async function tryToFetchProgress(cookies: string): Promise<HTMLElement> {
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);

View file

@ -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);

View file

@ -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';

View file

@ -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);
}

View file

@ -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
) {}
}

View file

@ -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);
});