diff --git a/api/claude-service.ts b/api/claude-service.ts index 055d9e6..a82ab91 100644 --- a/api/claude-service.ts +++ b/api/claude-service.ts @@ -3,7 +3,16 @@ import { CLAUDE, MCQS, MCQ, API } from '../ui/constants'; import SpaceforgePlugin from '../main'; import { MCQQuestion, MCQSet } from '../models/mcq'; import { IMCQGenerationService } from './mcq-generation-service'; -import { SpaceforgeSettings, MCQQuestionAmountMode, MCQDifficulty } from '../models/settings'; // Import MCQQuestionAmountMode +import { SpaceforgeSettings, MCQQuestionAmountMode, MCQDifficulty } from '../models/settings'; + +interface ClaudeResponse { + content: Array<{ text: string }>; +} + +interface ClaudeErrorResponse { + error?: { message?: string }; + message?: string; +} export class ClaudeService implements IMCQGenerationService { plugin: SpaceforgePlugin; @@ -105,17 +114,18 @@ export class ClaudeService implements IMCQGenerationService { }); if (response.status !== 200) { - const errorData = response.json || { message: response.text }; - throw new Error(`API request failed (${response.status}): ${errorData.error?.message || errorData.message || 'Unknown error'}`); + const errorData: ClaudeErrorResponse = response.json ?? { message: response.text }; + throw new Error(`API request failed (${response.status}): ${errorData.error?.message ?? errorData.message ?? 'Unknown error'}`); } - const data = response.json; - if (!data.content || !data.content.length || !data.content[0].text) { + const data = response.json as ClaudeResponse; + if (!data.content?.length || !data.content[0]?.text) { throw new Error('Invalid API response format from Claude - missing content'); } return data.content[0].text; } catch (error) { - new Notice(`Claude API error: ${error.message}`); + const msg = error instanceof Error ? error.message : String(error); + new Notice(`Claude API error: ${msg}`); throw error; } } diff --git a/api/gemini-service.ts b/api/gemini-service.ts index 0a925c3..15a18be 100644 --- a/api/gemini-service.ts +++ b/api/gemini-service.ts @@ -3,9 +3,16 @@ import { GEMINI, MCQS, MCQ, API } from '../ui/constants'; import SpaceforgePlugin from '../main'; import { MCQQuestion, MCQSet } from '../models/mcq'; import { IMCQGenerationService } from './mcq-generation-service'; -import { SpaceforgeSettings, MCQQuestionAmountMode, MCQDifficulty } from '../models/settings'; // Import MCQQuestionAmountMode +import { SpaceforgeSettings, MCQQuestionAmountMode, MCQDifficulty } from '../models/settings'; +interface GeminiResponse { + candidates: Array<{ content: { parts: Array<{ text: string }> } }>; +} +interface GeminiErrorResponse { + error?: { message?: string }; + message?: string; +} export class GeminiService implements IMCQGenerationService { plugin: SpaceforgePlugin; @@ -104,24 +111,24 @@ export class GeminiService implements IMCQGenerationService { }); if (response.status !== 200) { - const errorData = response.json; - const errorMessage = errorData?.error?.message || errorData?.message || 'Unknown error'; + const errorData = response.json as GeminiErrorResponse; + const errorMessage = errorData?.error?.message ?? errorData?.message ?? 'Unknown error'; throw new Error(`API request failed (${response.status}): ${errorMessage}`); } - const data = response.json; - // Gemini response structure: data.candidates[0].content.parts[0].text - if (!data.candidates || !data.candidates.length || !data.candidates[0].content || !data.candidates[0].content.parts || !data.candidates[0].content.parts.length || !data.candidates[0].content.parts[0].text) { + const data = response.json as GeminiResponse; + if (!data.candidates?.length || !data.candidates[0]?.content?.parts?.length || !data.candidates[0]?.content?.parts[0]?.text) { throw new Error('Invalid API response format from Gemini - missing content'); } return data.candidates[0].content.parts[0].text; } catch (error) { - new Notice(`Gemini API error: ${error.message}`); + const msg = error instanceof Error ? error.message : String(error); + new Notice(`Gemini API error: ${msg}`); throw error; } } - private parseResponse(response: string, settings: SpaceforgeSettings, numQuestionsToGenerate: number): MCQQuestion[] { + private parseResponse(response: string, _settings: SpaceforgeSettings, numQuestionsToGenerate: number): MCQQuestion[] { const questions: MCQQuestion[] = []; try { const questionBlocks: string[] = response.split(/\d+\.\s+/).filter(block => block.trim().length > 0); diff --git a/api/ollama-service.ts b/api/ollama-service.ts index 9158507..44795f3 100644 --- a/api/ollama-service.ts +++ b/api/ollama-service.ts @@ -3,7 +3,11 @@ import { OLLAMA, API } from '../ui/constants'; import SpaceforgePlugin from '../main'; import { MCQQuestion, MCQSet } from '../models/mcq'; import { IMCQGenerationService } from './mcq-generation-service'; -import { SpaceforgeSettings, MCQQuestionAmountMode, MCQDifficulty } from '../models/settings'; // Import MCQQuestionAmountMode +import { SpaceforgeSettings, MCQQuestionAmountMode, MCQDifficulty } from '../models/settings'; + +interface OllamaResponse { + message: { role: string; content: string }; +} export class OllamaService implements IMCQGenerationService { plugin: SpaceforgePlugin; @@ -14,7 +18,7 @@ export class OllamaService implements IMCQGenerationService { async generateMCQs(notePath: string, noteContent: string, settings: SpaceforgeSettings): Promise { if (!settings.ollamaApiUrl) { - new Notice(`${OLLAMA} ${API} ${URL} not set in settings.`); + new Notice(`${OLLAMA} ${API} URL not set in settings.`); return null; } if (!settings.ollamaModel) { @@ -106,19 +110,19 @@ export class OllamaService implements IMCQGenerationService { throw new Error(`API request failed (${response.status}): ${errorText}`); } - const data = response.json; - // Ollama's non-streaming chat response structure is typically { model, created_at, message: { role, content }, done } - if (!data.message || !data.message.content) { + const data = response.json as OllamaResponse; + if (!data.message?.content) { throw new Error('Invalid API response format from Ollama - missing message content'); } return data.message.content; } catch (error) { - new Notice(`Ollama API error: ${error.message}`); + const msg = error instanceof Error ? error.message : String(error); + new Notice(`Ollama API error: ${msg}`); throw error; } } - private parseResponse(response: string, settings: SpaceforgeSettings, numQuestionsToGenerate: number): MCQQuestion[] { + private parseResponse(response: string, _settings: SpaceforgeSettings, numQuestionsToGenerate: number): MCQQuestion[] { const questions: MCQQuestion[] = []; try { const questionBlocks: string[] = response.split(/\d+\.\s+/).filter(block => block.trim().length > 0); diff --git a/api/openai-service.ts b/api/openai-service.ts index fe9b0c3..bec6b22 100644 --- a/api/openai-service.ts +++ b/api/openai-service.ts @@ -3,7 +3,16 @@ import { OPENAI, API } from '../ui/constants'; import SpaceforgePlugin from '../main'; import { MCQQuestion, MCQSet } from '../models/mcq'; import { IMCQGenerationService } from './mcq-generation-service'; -import { SpaceforgeSettings, MCQQuestionAmountMode, MCQDifficulty } from '../models/settings'; // Import MCQQuestionAmountMode +import { SpaceforgeSettings, MCQQuestionAmountMode, MCQDifficulty } from '../models/settings'; + +interface OpenAIResponse { + choices: Array<{ message: { content: string } }>; +} + +interface OpenAIErrorResponse { + error?: { message?: string }; + message?: string; +} export class OpenAIService implements IMCQGenerationService { plugin: SpaceforgePlugin; @@ -102,22 +111,23 @@ export class OpenAIService implements IMCQGenerationService { }); if (response.status !== 200) { - const errorData = response.json || { message: response.text }; - throw new Error(`API request failed (${response.status}): ${errorData.error?.message || errorData.message || 'Unknown error'}`); + const errorData: OpenAIErrorResponse = response.json ?? { message: response.text }; + throw new Error(`API request failed (${response.status}): ${errorData.error?.message ?? errorData.message ?? 'Unknown error'}`); } - const data = response.json; - if (!data.choices || !data.choices.length || !data.choices[0].message || !data.choices[0].message.content) { + const data = response.json as OpenAIResponse; + if (!data.choices?.length || !data.choices[0]?.message?.content) { throw new Error('Invalid API response format from OpenAI - missing content'); } return data.choices[0].message.content; } catch (error) { - new Notice(`OpenAI API error: ${error.message}`); + const msg = error instanceof Error ? error.message : String(error); + new Notice(`OpenAI API error: ${msg}`); throw error; } } - private parseResponse(response: string, settings: SpaceforgeSettings, numQuestionsToGenerate: number): MCQQuestion[] { + private parseResponse(response: string, _settings: SpaceforgeSettings, numQuestionsToGenerate: number): MCQQuestion[] { const questions: MCQQuestion[] = []; try { const questionBlocks: string[] = response.split(/\d+\.\s+/).filter(block => block.trim().length > 0); diff --git a/api/openrouter-service.ts b/api/openrouter-service.ts index 636d3d1..7613ef6 100644 --- a/api/openrouter-service.ts +++ b/api/openrouter-service.ts @@ -3,7 +3,12 @@ import { OPENROUTER, API } from '../ui/constants'; import SpaceforgePlugin from '../main'; import { MCQQuestion, MCQSet } from '../models/mcq'; import { IMCQGenerationService } from './mcq-generation-service'; -import { SpaceforgeSettings, MCQQuestionAmountMode, MCQDifficulty } from '../models/settings'; // Import MCQQuestionAmountMode +import { SpaceforgeSettings, MCQQuestionAmountMode, MCQDifficulty } from '../models/settings'; + +interface OpenRouterResponse { + choices: Array<{ message: { content: string } }>; +} + /** * Service for generating MCQs using the OpenRouter API @@ -171,15 +176,16 @@ For example: throw new Error(`API request failed (${response.status}): ${response.text}`); } - const data = response.json; + const data = response.json as OpenRouterResponse; - if (!data.choices || !data.choices.length || !data.choices[0].message) { + if (!data.choices?.length || !data.choices[0]?.message) { throw new Error('Invalid API response format from OpenRouter - missing choices'); } return data.choices[0].message.content; } catch (error) { - new Notice(`OpenRouter API error: ${error.message}`); + const msg = error instanceof Error ? error.message : String(error); + new Notice(`OpenRouter API error: ${msg}`); throw error; } } @@ -192,7 +198,7 @@ For example: * @param numQuestionsToGenerate The target number of questions expected * @returns Array of parsed MCQ questions */ - private parseResponse(response: string, settings: SpaceforgeSettings, numQuestionsToGenerate: number): MCQQuestion[] { + private parseResponse(response: string, _settings: SpaceforgeSettings, numQuestionsToGenerate: number): MCQQuestion[] { const questions: MCQQuestion[] = []; try { diff --git a/api/together-service.ts b/api/together-service.ts index 392b45f..e5159fd 100644 --- a/api/together-service.ts +++ b/api/together-service.ts @@ -3,7 +3,16 @@ import { TOGETHER_AI, API } from '../ui/constants'; import SpaceforgePlugin from '../main'; import { MCQQuestion, MCQSet } from '../models/mcq'; import { IMCQGenerationService } from './mcq-generation-service'; -import { SpaceforgeSettings, MCQQuestionAmountMode, MCQDifficulty } from '../models/settings'; // Import MCQQuestionAmountMode +import { SpaceforgeSettings, MCQQuestionAmountMode, MCQDifficulty } from '../models/settings'; + +interface TogetherResponse { + choices: Array<{ message: { content: string } }>; +} + +interface TogetherErrorResponse { + error?: { message?: string }; + message?: string; +} export class TogetherService implements IMCQGenerationService { plugin: SpaceforgePlugin; @@ -103,17 +112,18 @@ export class TogetherService implements IMCQGenerationService { }); if (response.status !== 200) { - const errorData = response.json || { message: response.text }; - throw new Error(`API request failed (${response.status}): ${errorData.error?.message || errorData.message || 'Unknown error'}`); + const errorData: TogetherErrorResponse = response.json ?? { message: response.text }; + throw new Error(`API request failed (${response.status}): ${errorData.error?.message ?? errorData.message ?? 'Unknown error'}`); } - const data = response.json; - if (!data.choices || !data.choices.length || !data.choices[0].message || !data.choices[0].message.content) { + const data = response.json as TogetherResponse; + if (!data.choices?.length || !data.choices[0]?.message?.content) { throw new Error('Invalid API response format from Together AI - missing content'); } return data.choices[0].message.content; } catch (error) { - new Notice(`Together AI API error: ${error.message}`); + const msg = error instanceof Error ? error.message : String(error); + new Notice(`Together AI API error: ${msg}`); throw error; } } diff --git a/controllers/review-controller-core.ts b/controllers/review-controller-core.ts index e7a50bc..b208e76 100644 --- a/controllers/review-controller-core.ts +++ b/controllers/review-controller-core.ts @@ -427,12 +427,12 @@ export class ReviewControllerCore implements IReviewController { if (schedule && this.plugin.settings.enableQuestionRegenerationOnRating && this.plugin.mcqService && typeof response === 'number') { if (schedule.schedulingAlgorithm === 'fsrs') { // FSRS: response is FsrsRating (1-4), setting is minFsrsRatingForQuestionRegeneration (1-4) - if (response >= this.plugin.settings.minFsrsRatingForQuestionRegeneration) { + if ((response as number) >= this.plugin.settings.minFsrsRatingForQuestionRegeneration) { triggerRegeneration = true; } } else { // SM-2 // SM-2: response is ReviewResponse (0-5), setting is minSm2RatingForQuestionRegeneration (0-5) - if (response >= this.plugin.settings.minSm2RatingForQuestionRegeneration) { + if ((response as number) >= this.plugin.settings.minSm2RatingForQuestionRegeneration) { triggerRegeneration = true; } } diff --git a/esbuild.config.mjs b/esbuild.config.mjs index 66c3e37..8b96608 100644 --- a/esbuild.config.mjs +++ b/esbuild.config.mjs @@ -1,6 +1,6 @@ import esbuild from "esbuild"; import process from "node:process"; -import builtins from "builtin-modules"; +import { builtinModules } from "node:module"; const banner = `/* @@ -32,7 +32,7 @@ const buildOptions = { '@lezer/highlight', '@lezer/lr', 'tslib', - ...builtins], + ...builtinModules], format: 'cjs', target: 'es2018', logLevel: "info", diff --git a/install.js b/install.js index ca17ffc..57ef958 100644 --- a/install.js +++ b/install.js @@ -1,4 +1,4 @@ -const fs = require('fs-extra'); +const fs = require('fs'); const path = require('path'); const { exec } = require('child_process'); const readline = require('readline'); @@ -40,7 +40,7 @@ function installPlugin(obsidianPluginsDir) { const pluginDir = path.join(obsidianPluginsDir, pluginName); // Ensure plugin directory exists - fs.ensureDirSync(pluginDir); + fs.mkdirSync(pluginDir, { recursive: true }); console.log('Installing plugin files...'); @@ -52,7 +52,7 @@ function installPlugin(obsidianPluginsDir) { const destPath = path.join(pluginDir, file); if (fs.existsSync(sourcePath)) { - fs.copySync(sourcePath, destPath, { overwrite: true }); + fs.copyFileSync(sourcePath, destPath); console.log(`✓ Copied ${file}`); } else { console.log(`⚠ Warning: ${file} not found in project directory`); diff --git a/main.ts b/main.ts index 3319782..cd581f8 100644 --- a/main.ts +++ b/main.ts @@ -258,7 +258,7 @@ export default class SpaceforgePlugin extends Plugin { try { this.loadData().then(loaded => { if (loaded) { - existingData = loaded; + existingData = loaded as Partial; } }).catch(() => { /* handle error */ }); } @@ -346,7 +346,7 @@ export default class SpaceforgePlugin extends Plugin { const file = this.app.vault.getAbstractFileByPath(effectivePath); if (file instanceof TFile) { const jsonData = await this.app.vault.read(file); - if (jsonData) rawLoadedData = JSON.parse(jsonData); + if (jsonData) rawLoadedData = JSON.parse(jsonData) as SpaceforgePluginData; new Notice(`Spaceforge: Loaded data from custom path: ${effectivePath}`, 3000); } else { // Custom path specified but file doesn't exist. @@ -357,7 +357,7 @@ export default class SpaceforgePlugin extends Plugin { try { const oldJsonData = await this.app.vault.read(oldFile); if (oldJsonData) { - rawLoadedData = JSON.parse(oldJsonData); + rawLoadedData = JSON.parse(oldJsonData) as SpaceforgePluginData; // Data will be saved to new path by savePluginData later } } catch { /* handle error */ } @@ -368,7 +368,7 @@ export default class SpaceforgePlugin extends Plugin { } } else { // Using default plugin storage path - rawLoadedData = await this.loadData(); // This is the plugin's internal save/load + rawLoadedData = await this.loadData() as SpaceforgePluginData | undefined; } let loadedSettings = {}; // Start with empty object @@ -444,9 +444,9 @@ export default class SpaceforgePlugin extends Plugin { // SIMPLE RECOVERY: Try localStorage backup once, then use defaults try { - const backupData = await this.app.loadLocalStorage('spaceforge-backup'); + const backupData: unknown = await this.app.loadLocalStorage('spaceforge-backup'); if (backupData && typeof backupData === 'string') { - const parsedBackup = JSON.parse(backupData); + const parsedBackup = JSON.parse(backupData) as { reviewData?: Partial; settings?: Partial }; if (parsedBackup.reviewData) { this.settings = { ...DEFAULT_SETTINGS, ...parsedBackup.settings }; this.pluginState = { ...DEFAULT_PLUGIN_STATE_DATA, ...parsedBackup.reviewData }; @@ -483,7 +483,7 @@ export default class SpaceforgePlugin extends Plugin { try { // Ensure settings object exists and is valid, applying defaults if necessary if (!this.settings || typeof this.settings !== 'object') { - this.settings = JSON.parse(JSON.stringify(DEFAULT_SETTINGS)); + this.settings = JSON.parse(JSON.stringify(DEFAULT_SETTINGS)) as SpaceforgeSettings; } else { // Ensure all default keys are present this.settings = { ...DEFAULT_SETTINGS, ...this.settings }; @@ -554,7 +554,8 @@ export default class SpaceforgePlugin extends Plugin { new Notice(`Successfully saved to custom path, original data file kept as backup for safety`, 5000); } } catch (writeError) { - new Notice(`Error saving data to custom path ${effectiveSavePath}: ${writeError.message}. Falling back to default path for this save.`, 10000); + const msg = writeError instanceof Error ? writeError.message : String(writeError); + new Notice(`Error saving data to custom path ${effectiveSavePath}: ${msg}. Falling back to default path for this save.`, 10000); // Fallback save to default location if custom path write fails try { await this.saveData(dataToSave); // Plugin's internal save @@ -717,7 +718,7 @@ export default class SpaceforgePlugin extends Plugin { // It's good practice to handle unexpected enum values, even if TypeScript provides some safety. // This could happen if settings data is corrupted or from an older version. // const exhaustiveCheck: never = this.settings.mcqApiProvider; // This will cause a type error now, which is good! - new Notice(`Unsupported MCQ API provider selected: ${this.settings.mcqApiProvider as any}`); + new Notice(`Unsupported MCQ API provider selected: ${String(this.settings.mcqApiProvider)}`); return undefined; } } diff --git a/manifest.json b/manifest.json index 58c9dc6..1444a5d 100644 --- a/manifest.json +++ b/manifest.json @@ -1,8 +1,8 @@ { "id": "spaceforge", "name": "Spaceforge", - "version": "1.0.4", - "minAppVersion": "0.15.0", + "version": "1.0.5", + "minAppVersion": "1.8.7", "description": "Enhance knowledge retention with spaced repetition using FSRS & SM-2 algorithms, AI-powered MCQ generation, integrated Pomodoro timer, and calendar event manager.", "author": "dralkh", "authorUrl": "https://github.com/dralkh", diff --git a/models/review-schedule.ts b/models/review-schedule.ts index 62d1876..27bfabb 100644 --- a/models/review-schedule.ts +++ b/models/review-schedule.ts @@ -129,7 +129,7 @@ export enum ReviewResponse { */ export function toSM2Quality(response: ReviewResponse): number { // Ensure response is within 0-5 range - if (response >= 0 && response <= 5) { + if (response as number >= 0 && response as number <= 5) { return response; } // Default fallback diff --git a/package.json b/package.json index ab0771f..5b2a6a2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "spaceforge", - "version": "1.0.4", + "version": "1.0.5", "description": "A spaced repetition plugin for efficient knowledge review in Obsidian", "main": "main.js", "scripts": { @@ -20,11 +20,9 @@ "license": "MIT", "devDependencies": { "@eslint/js": "^9.39.1", - "@types/fs-extra": "^11.0.4", "@types/node": "^16.11.6", "@typescript-eslint/eslint-plugin": "^8.48.1", "@typescript-eslint/parser": "^8.48.1", - "builtin-modules": "3.3.0", "esbuild": "^0.17.19", "eslint": "^8.57.1", "eslint-plugin-obsidianmd": "^0.1.9", @@ -35,7 +33,6 @@ "typescript-eslint": "^8.48.1" }, "dependencies": { - "fs-extra": "^11.1.1", "ts-fsrs": "^4.7.1" } } \ No newline at end of file diff --git a/services/calendar-event-service.ts b/services/calendar-event-service.ts index daff9fe..302e7da 100644 --- a/services/calendar-event-service.ts +++ b/services/calendar-event-service.ts @@ -292,7 +292,7 @@ export class CalendarEventService { */ importEvents(json: string): number { try { - const events: CalendarEvent[] = JSON.parse(json); + const events = JSON.parse(json) as CalendarEvent[]; let importedCount = 0; events.forEach(event => { diff --git a/services/fsrs-schedule-service.ts b/services/fsrs-schedule-service.ts index 0e6d6ba..47ad446 100644 --- a/services/fsrs-schedule-service.ts +++ b/services/fsrs-schedule-service.ts @@ -63,7 +63,7 @@ export class FsrsScheduleService { case FsrsRating.Hard: return TsFsrsRating.Hard; case FsrsRating.Good: return TsFsrsRating.Good; case FsrsRating.Easy: return TsFsrsRating.Easy; - default: throw new Error(`Unknown FsrsRating: ${rating as any}`); + default: throw new Error(`Unknown FsrsRating: ${String(rating)}`); } } diff --git a/services/review-schedule-service.ts b/services/review-schedule-service.ts index 94c75da..f050172 100644 --- a/services/review-schedule-service.ts +++ b/services/review-schedule-service.ts @@ -319,7 +319,7 @@ export class ReviewScheduleService { newEase = Math.max(1.3, newEase); schedule.ease = Math.round(newEase * 100); - if (qualityRating >= ReviewResponse.CorrectWithDifficulty) { + if (qualityRating >= (ReviewResponse.CorrectWithDifficulty as number)) { schedule.consecutive += 1; if (qualityRating >= 3) { // repetitionCount for initial phase should increment if successful, reset if not. @@ -342,7 +342,7 @@ export class ReviewScheduleService { schedule.ease = ease; schedule.repetitionCount = repetitionCount; - if (qualityRating >= ReviewResponse.CorrectWithDifficulty) { + if (qualityRating >= (ReviewResponse.CorrectWithDifficulty as number)) { schedule.consecutive += 1; } else { schedule.consecutive = 0; diff --git a/styles/_components.css b/styles/_components.css index c22e437..7f3a93c 100644 --- a/styles/_components.css +++ b/styles/_components.css @@ -161,35 +161,22 @@ } /* ====== Utility Classes ====== */ -.sf-hidden { - display: none !important; +.sf-hidden.sf-hidden { + display: none; } -.sf-visible { - display: block !important; +.sf-visible.sf-visible { + display: block; } -.sf-flex { - display: flex !important; +.sf-flex.sf-flex { + display: flex; } -.sf-invisible { - opacity: 0 !important; +.sf-invisible.sf-invisible { + opacity: 0; } -.sf-visible-opacity { - opacity: 1 !important; -} - -/* ====== Display Utilities ====== */ -.sf-hidden { - display: none !important; -} - -.sf-visible { - display: block !important; -} - -.sf-flex { - display: flex !important; +.sf-visible-opacity.sf-visible-opacity { + opacity: 1; } diff --git a/styles/_variables.css b/styles/_variables.css index c9b698d..92d760b 100644 --- a/styles/_variables.css +++ b/styles/_variables.css @@ -27,8 +27,8 @@ --sf-recurring-bg: rgba(94, 129, 172, 0.05); /* Very light blue tint to match accent */ /* Text colors */ - --sf-text: var(--text-normal, #333); - --sf-text-muted: var(--text-muted, #888); + --sf-text: var(--text-normal, #333333); + --sf-text-muted: var(--text-muted, #888888); --sf-text-on-primary: var(--text-on-accent, white); /* Background colors */ diff --git a/styles/calendar.css b/styles/calendar.css index 7f26677..1fb4e5f 100644 --- a/styles/calendar.css +++ b/styles/calendar.css @@ -48,35 +48,6 @@ padding: 2px 0; /* Further reduced padding */ } -.is-collapsed .calendar-day { - min-height: 40px; /* Further reduced minimum height */ - padding: 2px; /* Further reduced padding */ - font-size: 10px; /* Further smaller font size */ - border-radius: 3px; /* Further smaller border radius */ -} - -.is-collapsed .calendar-day-number { - font-size: 11px; /* Further smaller font size */ - margin-bottom: 1px; /* Further reduced margin */ -} - -.is-collapsed .calendar-day.today .calendar-day-number::after { - width: 10px; /* Further reduced underline width */ -} - -.is-collapsed .calendar-review-count { - width: 16px; /* Further smaller size */ - height: 16px; /* Further smaller size */ - font-size: 8px; /* Further smaller font size */ - top: 2px; /* Adjusted position */ - right: 2px; /* Adjusted position */ -} - -.is-collapsed .calendar-time-estimate { - font-size: 8px; /* Further smaller font size */ - padding: 0 2px; /* Further reduced padding */ -} - .is-collapsed .calendar-day { min-height: 40px; /* Reduced minimum height */ padding: 4px; /* Reduced padding */ @@ -866,11 +837,6 @@ } } -/* Day hover add event button */ -.calendar-day { - position: relative; -} - .calendar-day-add-event { position: absolute; top: 2px; @@ -925,6 +891,7 @@ max-width: 600px; max-height: 90vh; overflow-y: auto; + animation: modalSlideIn 0.3s ease-out; } .event-modal .modal-content { @@ -1014,6 +981,7 @@ outline: none; border-color: var(--interactive-accent); box-shadow: 0 0 0 3px rgba(var(--interactive-accent-rgb), 0.1); + transform: translateY(-1px); } .event-modal-input:hover, @@ -1225,10 +1193,6 @@ } } -/* Animations */ -.event-modal { - animation: modalSlideIn 0.3s ease-out; -} @keyframes modalSlideIn { from { @@ -1241,13 +1205,6 @@ } } -/* Focus States */ -.event-modal-input:focus, -.event-modal-textarea:focus, -.event-modal-select:focus { - transform: translateY(-1px); -} - /* Success/Error States */ .event-modal-input.error, .event-modal-textarea.error, @@ -1281,54 +1238,7 @@ to { transform: rotate(360deg); } } -/* Compact Event Modal Styles */ -.event-modal { - max-width: 500px; - max-height: 85vh; -} - -.event-modal .modal-content { - border-radius: 8px; -} - -/* Compact Header */ -.event-modal-header { - display: flex; - align-items: center; - gap: var(--sf-space-sm); - padding: var(--sf-space-md) var(--sf-space-lg); - background: var(--interactive-accent); - color: var(--text-on-accent); - border-radius: 8px 8px 0 0; -} - -.event-modal-header-icon { - width: 24px; - height: 24px; - display: flex; - align-items: center; - justify-content: center; - background-color: rgba(255, 255, 255, 0.2); - border-radius: 50%; - font-size: 14px; -} - -.event-modal-header-text { - flex: 1; -} - -.event-modal-title { - margin: 0; - font-size: 18px; - font-weight: 600; - color: var(--text-on-accent); -} - /* Compact Form Layout */ -.event-modal-form { - padding: var(--sf-space-md); -} - .event-modal-row { display: flex; gap: var(--sf-space-sm); @@ -1346,63 +1256,6 @@ gap: 2px; } -.event-modal-label { - font-size: 12px; - font-weight: 600; - color: var(--text-normal); - margin: 0; -} - -.event-modal-label.required::after { - content: " *"; - color: var(--text-error); -} - -.event-modal-input, -.event-modal-textarea, -.event-modal-select { - width: 100%; - padding: 6px 8px; - border: 1px solid var(--background-modifier-border); - border-radius: 4px; - font-size: 13px; - background-color: var(--background-primary); - color: var(--text-normal); - transition: border-color 0.2s ease; - box-sizing: border-box; -} - -.event-modal-input:focus, -.event-modal-textarea:focus, -.event-modal-select:focus { - outline: none; - border-color: var(--interactive-accent); -} - -.event-modal-textarea { - resize: vertical; - min-height: 40px; - font-family: inherit; -} - -/* Compact Checkbox */ -.event-modal-checkbox { - width: 16px; - height: 16px; - accent-color: var(--interactive-accent); - cursor: pointer; - margin-right: 6px; -} - -.event-modal-checkbox-label { - font-size: 13px; - color: var(--text-normal); - cursor: pointer; - user-select: none; - display: flex; - align-items: center; -} - /* Compact Color Picker */ .event-modal-color-picker-compact { display: flex; @@ -1410,15 +1263,6 @@ gap: 6px; } -.event-modal-color-input { - width: 32px; - height: 28px; - border: 1px solid var(--background-modifier-border); - border-radius: 4px; - cursor: pointer; - padding: 1px; -} - /* Recurrence End Date Row */ .event-modal-recurrence-end-row { display: none; @@ -1428,47 +1272,7 @@ display: flex; } -/* Compact Actions */ -.event-modal-actions { - display: flex; - gap: var(--sf-space-sm); - justify-content: flex-end; - padding: var(--sf-space-md) var(--sf-space-lg); - border-top: 1px solid var(--background-modifier-border); - background-color: var(--background-secondary); - margin: 0 -var(--sf-space-md) -var(--sf-space-md); - border-radius: 0 0 8px 8px; -} - -.event-modal-btn { - padding: 6px 16px; - border-radius: 4px; - border: none; - font-size: 13px; - font-weight: 500; - cursor: pointer; - transition: all 0.2s ease; - min-width: 80px; -} - -.event-modal-btn-primary { - background-color: var(--interactive-accent); - color: var(--text-on-accent); -} - -.event-modal-btn-primary:hover:not(:disabled) { - background-color: var(--interactive-accent-hover); -} - -.event-modal-btn-secondary { - background-color: var(--background-modifier-border); - color: var(--text-normal); -} - -.event-modal-btn-secondary:hover { - background-color: var(--background-modifier-border-hover); -} - +/* Danger Button */ .event-modal-btn-danger { background-color: var(--color-red, #dc3545); color: white; @@ -1479,36 +1283,31 @@ transform: translateY(-1px); } -.event-modal-btn:disabled { - opacity: 0.5; - cursor: not-allowed; -} - /* Responsive Compact Design */ @media (max-width: 600px) { .event-modal { max-width: 95vw; margin: var(--sf-space-sm); } - + .event-modal-row { flex-direction: column; gap: var(--sf-space-xs); } - + .event-modal-header { padding: var(--sf-space-sm) var(--sf-space-md); } - + .event-modal-form { padding: var(--sf-space-sm); } - + .event-modal-actions { padding: var(--sf-space-sm) var(--sf-space-md); flex-direction: row; } - + .event-modal-btn { flex: 1; min-width: auto; @@ -1569,17 +1368,3 @@ -webkit-box-orient: vertical; } -/* Remove some of the previous enhanced styles to avoid conflicts */ -.event-modal-datetime-section, -.event-modal-datetime-grid, -.event-modal-input-group, -.event-modal-input-icon, -.event-modal-all-day-container, -.event-modal-category-color-grid, -.event-modal-category-container, -.event-modal-color-container, -.event-modal-color-label, -.event-modal-recurrence-container, -.event-modal-recurrence-end-container { - display: none; -} diff --git a/styles/mcq.css b/styles/mcq.css index ba43633..634646e 100644 --- a/styles/mcq.css +++ b/styles/mcq.css @@ -116,7 +116,6 @@ flex-direction: column; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); flex-grow: 1; /* Allow to grow and take available space */ - overflow-y: auto; /* Add scrolling if content overflows */ } /* Improve question text visibility */ @@ -131,37 +130,37 @@ } /* Ensure the MCQ modal takes more space */ -.spaceforge-mcq-modal.modal-content { +.spaceforge-mcq-modal.modal-content.spaceforge-mcq-modal { min-width: 500px; /* Ensure modal has minimum width */ max-width: 90vw; /* Allow up to 90% of viewport width */ min-height: 300px; /* Ensure minimum height */ - padding: 28px !important; + padding: 28px; display: flex; /* Make modal content a flex container */ flex-direction: column; /* Stack children vertically */ } /* Enhanced progress indicator with more granular steps */ -[data-progress="0"] .mcq-progress::before { width: 0% !important; } -[data-progress="5"] .mcq-progress::before { width: 5% !important; } -[data-progress="10"] .mcq-progress::before { width: 10% !important; } -[data-progress="15"] .mcq-progress::before { width: 15% !important; } -[data-progress="20"] .mcq-progress::before { width: 20% !important; } -[data-progress="25"] .mcq-progress::before { width: 25% !important; } -[data-progress="30"] .mcq-progress::before { width: 30% !important; } -[data-progress="35"] .mcq-progress::before { width: 35% !important; } -[data-progress="40"] .mcq-progress::before { width: 40% !important; } -[data-progress="45"] .mcq-progress::before { width: 45% !important; } -[data-progress="50"] .mcq-progress::before { width: 50% !important; } -[data-progress="55"] .mcq-progress::before { width: 55% !important; } -[data-progress="60"] .mcq-progress::before { width: 60% !important; } -[data-progress="65"] .mcq-progress::before { width: 65% !important; } -[data-progress="70"] .mcq-progress::before { width: 70% !important; } -[data-progress="75"] .mcq-progress::before { width: 75% !important; } -[data-progress="80"] .mcq-progress::before { width: 80% !important; } -[data-progress="85"] .mcq-progress::before { width: 85% !important; } -[data-progress="90"] .mcq-progress::before { width: 90% !important; } -[data-progress="95"] .mcq-progress::before { width: 95% !important; } -[data-progress="100"] .mcq-progress::before { width: 100% !important; } +[data-progress="0"] .mcq-progress::before { width: 0%; } +[data-progress="5"] .mcq-progress::before { width: 5%; } +[data-progress="10"] .mcq-progress::before { width: 10%; } +[data-progress="15"] .mcq-progress::before { width: 15%; } +[data-progress="20"] .mcq-progress::before { width: 20%; } +[data-progress="25"] .mcq-progress::before { width: 25%; } +[data-progress="30"] .mcq-progress::before { width: 30%; } +[data-progress="35"] .mcq-progress::before { width: 35%; } +[data-progress="40"] .mcq-progress::before { width: 40%; } +[data-progress="45"] .mcq-progress::before { width: 45%; } +[data-progress="50"] .mcq-progress::before { width: 50%; } +[data-progress="55"] .mcq-progress::before { width: 55%; } +[data-progress="60"] .mcq-progress::before { width: 60%; } +[data-progress="65"] .mcq-progress::before { width: 65%; } +[data-progress="70"] .mcq-progress::before { width: 70%; } +[data-progress="75"] .mcq-progress::before { width: 75%; } +[data-progress="80"] .mcq-progress::before { width: 80%; } +[data-progress="85"] .mcq-progress::before { width: 85%; } +[data-progress="90"] .mcq-progress::before { width: 90%; } +[data-progress="95"] .mcq-progress::before { width: 95%; } +[data-progress="100"] .mcq-progress::before { width: 100%; } /* ====== MCQ Warning Message ====== */ .mcq-attempt-warning { @@ -211,7 +210,8 @@ line-height: 1.4; color: var(--text-normal); position: relative; - /* overflow: hidden; Removed to prevent clipping */ + overflow: hidden; + z-index: 1; min-height: auto; /* Allow button to grow with content */ height: auto; /* Allow button to grow with content */ margin-bottom: 6px; @@ -305,17 +305,17 @@ } /* MCQ Choice Correct/Incorrect Styling - fixed dimensions with modern colors */ -.mcq-choice-correct { - background-color: var(--sf-success-light) !important; /* Modern green with lower opacity */ - border-color: var(--sf-success) !important; /* Modern green */ - color: var(--text-normal) !important; - box-shadow: 0 2px 8px rgba(56, 161, 105, 0.1) !important; +.mcq-choice-correct.mcq-choice-correct { + background-color: var(--sf-success-light); /* Modern green with lower opacity */ + border-color: var(--sf-success); /* Modern green */ + color: var(--text-normal); + box-shadow: 0 2px 8px rgba(56, 161, 105, 0.1); animation: correctPulse 0.5s ease-out; - transform: none !important; /* Prevent layout shifts */ + transform: none; /* Prevent layout shifts */ } -.mcq-choice-correct::before { - background-color: var(--sf-success) !important; /* Modern green */ +.mcq-choice-correct.mcq-choice-correct::before { + background-color: var(--sf-success); /* Modern green */ width: 6px; } @@ -323,16 +323,16 @@ color: var(--sf-success); /* Modern green */ } -.mcq-choice-incorrect { - background-color: var(--sf-danger-light) !important; /* Modern red with lower opacity */ - border-color: var(--sf-danger) !important; /* Modern red */ - color: var(--text-normal) !important; +.mcq-choice-incorrect.mcq-choice-incorrect { + background-color: var(--sf-danger-light); /* Modern red with lower opacity */ + border-color: var(--sf-danger); /* Modern red */ + color: var(--text-normal); animation: none; /* Remove the shake animation to prevent layout shifts */ - box-shadow: 0 2px 8px rgba(229, 62, 62, 0.1) !important; + box-shadow: 0 2px 8px rgba(229, 62, 62, 0.1); } -.mcq-choice-incorrect::before { - background-color: var(--sf-danger) !important; /* Modern red */ +.mcq-choice-incorrect.mcq-choice-incorrect::before { + background-color: var(--sf-danger); /* Modern red */ width: 6px; } @@ -681,10 +681,10 @@ color: white; } -.batch-review-cancel-button { +.batch-review-cancel-button.batch-review-cancel-button { background-color: var(--sf-bg-secondary); color: var(--sf-text); - border: 1px solid var(--background-modifier-border) !important; + border: 1px solid var(--background-modifier-border); } .batch-review-progress { @@ -748,15 +748,106 @@ margin-left: 10px; } -.batch-review-complete-blackout, -.batch-review-incorrect, -.batch-review-incorrect-familiar, -.batch-review-correct-difficulty, -.batch-review-correct-hesitation, -.batch-review-perfect-recall, -.batch-review-hard, -.batch-review-fair, -.batch-review-good, +.batch-review-complete-blackout { + padding: 5px 10px; + border-radius: 100px; + min-width: 100px; + text-align: center; + font-weight: 500; + font-size: 13px; + background-color: var(--sf-danger-light); + color: var(--sf-danger); +} + +.batch-review-incorrect { + padding: 5px 10px; + border-radius: 100px; + min-width: 100px; + text-align: center; + font-weight: 500; + font-size: 13px; + background-color: var(--sf-danger-light); + color: var(--sf-danger); +} + +.batch-review-incorrect-familiar { + padding: 5px 10px; + border-radius: 100px; + min-width: 100px; + text-align: center; + font-weight: 500; + font-size: 13px; + background-color: var(--sf-danger-light); + color: var(--sf-danger); +} + +.batch-review-correct-difficulty { + padding: 5px 10px; + border-radius: 100px; + min-width: 100px; + text-align: center; + font-weight: 500; + font-size: 13px; + background-color: var(--sf-success-light); + color: var(--sf-success); +} + +.batch-review-correct-hesitation { + padding: 5px 10px; + border-radius: 100px; + min-width: 100px; + text-align: center; + font-weight: 500; + font-size: 13px; + background-color: var(--sf-success-light); + color: var(--sf-success); +} + +.batch-review-perfect-recall { + padding: 5px 10px; + border-radius: 100px; + min-width: 100px; + text-align: center; + font-weight: 500; + font-size: 13px; + background-color: var(--sf-success-light); + color: var(--sf-success); +} + +/* Legacy result styles */ +.batch-review-hard { + padding: 5px 10px; + border-radius: 100px; + min-width: 100px; + text-align: center; + font-weight: 500; + font-size: 13px; + background-color: var(--sf-danger-light); + color: var(--sf-danger); +} + +.batch-review-fair { + padding: 5px 10px; + border-radius: 100px; + min-width: 100px; + text-align: center; + font-weight: 500; + font-size: 13px; + background-color: var(--sf-warning-light); + color: var(--sf-warning); +} + +.batch-review-good { + padding: 5px 10px; + border-radius: 100px; + min-width: 100px; + text-align: center; + font-weight: 500; + font-size: 13px; + background-color: var(--sf-success-light); + color: var(--sf-success); +} + .batch-review-perfect { padding: 5px 10px; border-radius: 100px; @@ -764,55 +855,6 @@ text-align: center; font-weight: 500; font-size: 13px; -} - -.batch-review-complete-blackout { - background-color: var(--sf-danger-light); - color: var(--sf-danger); -} - -.batch-review-incorrect { - background-color: var(--sf-danger-light); - color: var(--sf-danger); -} - -.batch-review-incorrect-familiar { - background-color: var(--sf-danger-light); /* Using light danger variable */ - color: var(--sf-danger); /* Using danger variable */ -} - -.batch-review-correct-hesitation { - background-color: var(--sf-success-light); /* Using light success variable */ - color: var(--sf-success); /* Using success variable */ -} - -/* Legacy result styles */ -.batch-review-hard { - background-color: var(--sf-danger-light); - color: var(--sf-danger); -} - -.batch-review-fair { - background-color: var(--sf-warning-light); - color: var(--sf-warning); -} - -.batch-review-good { - background-color: var(--sf-success-light); /* Using light success variable */ - color: var(--sf-success); /* Using success variable */ -} - -.batch-review-perfect { - background-color: var(--sf-success-light); - color: var(--sf-success); -} - -.batch-review-good { - background-color: var(--sf-success-light); - color: var(--sf-success); -} - -.batch-review-perfect { background-color: var(--sf-success-light); color: var(--sf-success); } @@ -837,12 +879,6 @@ } /* Additional MCQ enhancements */ -.mcq-choice-btn { - position: relative; - overflow: hidden; - z-index: 1; -} - .mcq-choice-btn::after { content: ''; position: absolute; @@ -888,19 +924,19 @@ } /* Fix for letter indicators in MCQ UI */ -[class*=" or "], [class^="or "] { - background-color: var(--sf-bg-primary) !important; - color: var(--sf-text) !important; - border: 1px solid var(--background-modifier-border) !important; - padding: 2px 6px !important; - border-radius: 4px !important; +[class*=" or "][class*=" or "], [class^="or "][class^="or "] { + background-color: var(--sf-bg-primary); + color: var(--sf-text); + border: 1px solid var(--background-modifier-border); + padding: 2px 6px; + border-radius: 4px; } /* Preserve legacy class function while improving appearance */ /* Style for the selected answer using keyboard navigation */ -.mcq-choice-selected { - border-color: var(--interactive-accent) !important; +.mcq-choice-selected.mcq-choice-selected { + border-color: var(--interactive-accent); box-shadow: 0 0 0 2px rgba(var(--interactive-accent-rgb), 0.5), 0 1px 3px rgba(0, 0, 0, 0.1); transform: translateX(4px); /* Consistent with hover */ } @@ -912,16 +948,14 @@ } /* Dark theme specific overrides for text visibility - MORE SPECIFIC */ -.theme-dark .spaceforge-mcq-modal .mcq-choice-btn { - color: var(--text-normal) !important; /* Attempt with !important if necessary */ +.theme-dark .spaceforge-mcq-modal .mcq-choice-btn.mcq-choice-btn { + color: var(--text-normal); } -.theme-dark .spaceforge-mcq-modal .mcq-choice-btn .mcq-choice-text { - color: var(--text-normal) !important; /* Attempt with !important if necessary */ +.theme-dark .spaceforge-mcq-modal .mcq-choice-btn .mcq-choice-text.mcq-choice-text { + color: var(--text-normal); } -.theme-dark .spaceforge-mcq-modal .mcq-choice-btn .mcq-shortcut-hint { - color: var(--text-muted) !important; /* Attempt with !important if necessary */ - /* Consider a lighter background for the hint if still problematic */ - /* background-color: var(--background-modifier-hover) !important; */ +.theme-dark .spaceforge-mcq-modal .mcq-choice-btn .mcq-shortcut-hint.mcq-shortcut-hint { + color: var(--text-muted); } /* Styles for Algorithm Details in Results */ diff --git a/styles/pomodoro.css b/styles/pomodoro.css index 6560b40..3610fcc 100644 --- a/styles/pomodoro.css +++ b/styles/pomodoro.css @@ -1,6 +1,7 @@ /* Pomodoro Styles */ -.pomodoro-visibility-toggle-container { - display: none !important; /* Hide the old toggle button */ +.pomodoro-visibility-toggle-container.pomodoro-visibility-toggle-container { + display: none; /* Hide the old toggle button */ + margin-bottom: 8px; /* Space between toggle and timer content */ } .sidebar-pomodoro-section { @@ -25,10 +26,6 @@ box-sizing: border-box; /* Ensure padding and border are within width */ } -.pomodoro-visibility-toggle-container { - margin-bottom: 8px; /* Space between toggle and timer content */ -} - .pomodoro-visibility-toggle-container .pomodoro-visibility-toggle-btn { width: 100%; padding: 6px 12px; diff --git a/styles/review-buttons.css b/styles/review-buttons.css index f17071f..1d2f6b4 100644 --- a/styles/review-buttons.css +++ b/styles/review-buttons.css @@ -158,9 +158,9 @@ .review-note-button:disabled, /* General class for individual note buttons */ .review-bulk-button:disabled, /* General class for bulk action buttons */ .review-date-action-button:disabled, /* General class for date section buttons */ -button.disabled { /* Fallback for any button with .disabled class */ +button.disabled.disabled { /* Fallback for any button with .disabled class */ opacity: 0.5; - cursor: not-allowed !important; /* Ensure cursor changes */ + cursor: not-allowed; /* Ensure cursor changes */ filter: grayscale(60%); box-shadow: none; } diff --git a/styles/settings.css b/styles/settings.css index c6dc290..f36a37e 100644 --- a/styles/settings.css +++ b/styles/settings.css @@ -164,9 +164,9 @@ } /* Enhance setting items */ -.setting-item { +.setting-item.setting-item { padding: var(--sf-space-sm) 0; - border-top: none !important; + border-top: none; } .setting-item-info { diff --git a/styles/sidebar.css b/styles/sidebar.css index bed5b3e..7317821 100644 --- a/styles/sidebar.css +++ b/styles/sidebar.css @@ -11,21 +11,38 @@ /* Upcoming Reviews Section */ .review-upcoming-section { - margin-top: 15px; + margin-top: var(--sf-space-lg); padding-top: 10px; border-top: 1px solid var(--background-modifier-border); } +.review-upcoming-section h3 { + font-size: 16px; + margin-bottom: var(--sf-space-sm); + color: var(--sf-text); + font-weight: 600; +} + .review-upcoming-list { + margin-top: var(--sf-space-xs); display: flex; flex-direction: column; - gap: 5px; /* Space between day items */ + gap: var(--sf-space-xs); } .review-upcoming-day { - padding: 5px 8px; - border-radius: var(--radius-s); - transition: background-color 0.2s ease; + padding: var(--sf-space-xs) var(--sf-space-sm); + border-radius: var(--sf-radius-sm); + background-color: var(--sf-bg-secondary); + transition: var(--sf-transition); + border: 1px solid transparent; + display: flex; + justify-content: space-between; +} + +.review-upcoming-day:hover { + border-color: var(--interactive-accent); + transform: translateX(3px); } .review-upcoming-day.clickable { @@ -48,8 +65,11 @@ } .review-upcoming-day-count { - font-size: 0.9em; - color: var(--text-muted); + color: var(--sf-text-muted); + font-size: 12px; + background-color: var(--sf-bg-primary); + padding: 1px 6px; + border-radius: 100px; } /* Style for expanded day */ @@ -136,8 +156,8 @@ background-color: var(--text-accent); /* Using theme variable */ } -.review-stats-custom-order { - color: var(--interactive-accent) !important; /* Using theme variable */ +.review-stats-custom-order.review-stats-custom-order { + color: var(--interactive-accent); /* Using theme variable */ font-style: italic; font-size: 0.85em; display: flex; @@ -159,16 +179,16 @@ } /* Force ALL direct children to have zero margins to let gap control spacing */ -.review-buttons-container > * { - margin: 0 !important; /* Override any potential conflicting margins */ +.review-buttons-container.review-buttons-container > * { + margin: 0; /* Override any potential conflicting margins */ } -.review-all-button, -.review-all-mcq-button { +.review-all-button.review-all-button, +.review-all-mcq-button.review-all-mcq-button { width: 100%; padding: var(--sf-space-sm) var(--sf-space-md); - margin: 0 !important; /* Ensure no margin */ + margin: 0; /* Ensure no margin */ border-radius: var(--sf-radius-md); cursor: pointer; font-weight: 500; @@ -662,63 +682,18 @@ box-shadow: var(--sf-shadow-lg); /* Using defined shadow variable */ } -.review-upcoming-section { - margin-top: var(--sf-space-lg); -} - -.review-upcoming-section h3 { - font-size: 16px; - margin-bottom: var(--sf-space-sm); - color: var(--sf-text); - font-weight: 600; -} - -.review-upcoming-list { - margin-top: var(--sf-space-xs); - display: flex; - flex-direction: column; - gap: var(--sf-space-xs); -} - -.review-upcoming-day { - padding: var(--sf-space-xs) var(--sf-space-sm); - border-radius: var(--sf-radius-sm); - background-color: var(--sf-bg-secondary); - transition: var(--sf-transition); - border: 1px solid transparent; - display: flex; - justify-content: space-between; -} - -.review-upcoming-day:hover { - border-color: var(--interactive-accent); /* Using theme variable */ - transform: translateX(3px); -} - -.review-upcoming-day-name { - font-weight: 500; -} - -.review-upcoming-day-count { - color: var(--sf-text-muted); - font-size: 12px; - background-color: var(--sf-bg-primary); - padding: 1px 6px; - border-radius: 100px; -} - /* --- Pomodoro Timer Styles --- */ /* Styles for Pomodoro section when inside review-buttons-container */ .review-buttons-container .pomodoro-toggle-container { width: 100%; /* Make toggle container take full width */ - margin: 0 !important; /* Ensure no margin */ + margin: 0; /* Ensure no margin */ } .review-buttons-container .pomodoro-visibility-toggle-btn { width: 100%; padding: calc(var(--sf-space-xs) / 1.5) var(--sf-space-sm); /* Reduced vertical padding */ - margin: 0 !important; /* Ensure no margin */ + margin: 0; /* Ensure no margin */ border-radius: var(--sf-radius-md); cursor: pointer; font-weight: 500; @@ -735,13 +710,13 @@ .review-buttons-container .pomodoro-section-content { width: 100%; /* Make content take full width */ - margin: 0 !important; /* Ensure no margin */ + margin: 0; /* Ensure no margin */ } -.pomodoro-container { +.pomodoro-container.pomodoro-container { /* margin-top is removed as it's handled by pomodoro-toggle-container or pomodoro-section-content */ padding: 2px var(--sf-space-xs); /* Minimal vertical padding, keep horizontal */ - margin: 0 !important; /* Ensure no margin */ + margin: 0; /* Ensure no margin */ background-color: var(--background-secondary); /* Slightly different background */ border-radius: var(--radius-m); border: 1px solid var(--background-modifier-border); @@ -769,7 +744,8 @@ text-align: center; order: 2; /* Order for flex: Start(1) Timer(2) Skip(3) Cog(4) */ flex-grow: 1; /* Allow timer to take some space */ - border: none; /* Base border is none */ + border-left: 3px solid transparent; + border-right: 3px solid transparent; transition: border-color 0.3s ease; /* Transition border color */ } @@ -781,16 +757,8 @@ opacity: 1; visibility: visible; } -/* .timer-hidden is no longer used to hide, opacity is handled by .is-paused or .is-idle */ -/* Mode-specific styling (using border-left and border-right) */ -.pomodoro-timer-display { - border-left: 3px solid transparent; /* Default transparent border */ - border-right: 3px solid transparent; /* Default transparent border */ - background-color: var(--background-primary); /* Reset background */ - color: var(--text-normal); /* Reset text color */ -} .pomodoro-timer-display.mode-work { border-left-color: var(--interactive-accent); border-right-color: var(--interactive-accent); diff --git a/ui/batch-review-modal.ts b/ui/batch-review-modal.ts index 09293be..377e9d5 100644 --- a/ui/batch-review-modal.ts +++ b/ui/batch-review-modal.ts @@ -335,7 +335,7 @@ export class BatchReviewModal extends Modal { const resultItemEl = resultsListEl.createDiv("batch-review-result-item"); const file = this.plugin.app.vault.getAbstractFileByPath(result.path); const fileName = file instanceof TFile ? file.basename : result.path; - resultItemEl.createEl("div", { text: fileName, cls: "batch-review-result-filename" }); + resultItemEl.createDiv({ text: fileName, cls: "batch-review-result-filename" }); let responseText: string; let responseClass: string; switch (result.response) { case ReviewResponse.CompleteBlackout: responseText = "Complete Blackout (0)"; responseClass = "batch-review-complete-blackout"; break; @@ -346,9 +346,9 @@ export class BatchReviewModal extends Modal { case ReviewResponse.PerfectRecall: responseText = "Perfect Recall (5)"; responseClass = "batch-review-perfect-recall"; break; default: responseText = "Unknown"; responseClass = ""; } - resultItemEl.createEl("div", { text: responseText, cls: `batch-review-result-response ${responseClass}` }); + resultItemEl.createDiv({ text: responseText, cls: `batch-review-result-response ${responseClass}` }); if (result.score !== undefined) { - resultItemEl.createEl("div", { text: `MCQ Score: ${Math.round(result.score * 100)}%`, cls: "batch-review-result-mcq-score" }); + resultItemEl.createDiv({ text: `MCQ Score: ${Math.round(result.score * 100)}%`, cls: "batch-review-result-mcq-score" }); } } const closeButton = contentEl.createEl("button", { text: "Close", cls: "batch-review-close-button" }); diff --git a/ui/calendar-view.ts b/ui/calendar-view.ts index 5989f89..3faf620 100644 --- a/ui/calendar-view.ts +++ b/ui/calendar-view.ts @@ -250,7 +250,7 @@ export class CalendarView { const { year, month, firstDay, daysInMonth } = this.getCalendarData(); const totalCells = 42; // Standard 6 weeks * 7 days grid - let dayCells = Array.from(gridEl.querySelectorAll(".calendar-day")) as HTMLElement[]; + let dayCells = Array.from(gridEl.querySelectorAll(".calendar-day")); // Adjust number of day cell elements if necessary if (dayCells.length < totalCells) { @@ -571,7 +571,7 @@ export class CalendarView { this.hideEventTooltip(); // Create tooltip element - this.tooltipEl = document.body.createEl("div"); + this.tooltipEl = document.body.createDiv(); this.tooltipEl.className = "calendar-event-tooltip"; // Format event details diff --git a/ui/consolidated-mcq-modal.ts b/ui/consolidated-mcq-modal.ts index b458076..c2da9c6 100644 --- a/ui/consolidated-mcq-modal.ts +++ b/ui/consolidated-mcq-modal.ts @@ -568,13 +568,13 @@ export class ConsolidatedMCQModal extends Modal { const noteScoreEl = noteScoresEl.createDiv('mcq-note-score'); - noteScoreEl.createEl('div', { + noteScoreEl.createDiv({ text: noteScore.fileName, cls: 'mcq-note-score-title' }); const scorePercent = Math.round(noteScore.score * 100); - const scoreTextValueEl = noteScoreEl.createEl('div', { + const scoreTextValueEl = noteScoreEl.createDiv({ text: `Score: ${scorePercent}% (${noteScore.correctAnswers}/${noteScore.totalQuestions})`, cls: 'mcq-note-score-value' }); diff --git a/ui/context-menu.ts b/ui/context-menu.ts index 1d9be3a..4b26dec 100644 --- a/ui/context-menu.ts +++ b/ui/context-menu.ts @@ -26,7 +26,9 @@ export class ContextMenuHandler { register(): void { // Register for the 'file-menu' event, which handles both files and folders. this.plugin.registerEvent( - this.plugin.app.workspace.on("file-menu", this.handleFileMenuEvent.bind(this)) + this.plugin.app.workspace.on("file-menu", (menu: Menu, abstractFile: TAbstractFile) => { + this.handleFileMenuEvent(menu, abstractFile); + }) ); } diff --git a/ui/event-modal.ts b/ui/event-modal.ts index cdd0d65..8b230de 100644 --- a/ui/event-modal.ts +++ b/ui/event-modal.ts @@ -95,7 +95,7 @@ export class EventModal extends Modal { this.isAllDayToggle = allDayGroup.createEl("input", { type: "checkbox", cls: "event-modal-checkbox" - }) as HTMLInputElement; + }); this.isAllDayToggle.checked = this.event?.isAllDay ?? false; this.isAllDayToggle.addEventListener("change", () => this.toggleTimeInput()); @@ -147,7 +147,7 @@ export class EventModal extends Modal { this.colorInput = colorPickerContainer.createEl("input", { type: "color", cls: "event-modal-color-input" - }) as HTMLInputElement; + }); if (this.event?.color) { this.colorInput.value = this.event.color; diff --git a/ui/mcq-modal.ts b/ui/mcq-modal.ts index 7f554a4..863f9f1 100644 --- a/ui/mcq-modal.ts +++ b/ui/mcq-modal.ts @@ -177,9 +177,9 @@ export class MCQModal extends Modal { // Cleanup handled by Modal's onClose automatically if using this.scope.register // Original onClose logic for saving partial progress: - const originalOnClose = this.onClose; + const originalOnClose = this.onClose.bind(this); this.onClose = () => { - originalOnClose.call(this); + originalOnClose(); if (!this.session.completed && this.session.answers.length > 0) { // Session was closed prematurely but some answers were given this.session.completedAt = Date.now(); diff --git a/ui/review-modal.ts b/ui/review-modal.ts index 9f3419f..0ac7c1f 100644 --- a/ui/review-modal.ts +++ b/ui/review-modal.ts @@ -55,7 +55,7 @@ export class ReviewModal extends Modal { createSm2Button("5: Perfect recall", "review-button review-button-perfect-recall", ReviewResponse.PerfectRecall); } - buttonsContainer.createEl("div", { cls: "review-button-separator" }); + buttonsContainer.createDiv({ cls: "review-button-separator" }); // Postpone Button const postponeButton = buttonsContainer.createEl("button", { text: "Postpone to tomorrow", cls: "review-button review-button-postpone" }); @@ -75,7 +75,7 @@ export class ReviewModal extends Modal { // MCQ Buttons (if enabled) if (this.plugin.settings.enableMCQ) { - buttonsContainer.createEl("div", { cls: "review-button-separator" }); + buttonsContainer.createDiv({ cls: "review-button-separator" }); const mcqButton = buttonsContainer.createEl("button", { cls: "review-button review-button-mcq" }); diff --git a/ui/settings-tab.ts b/ui/settings-tab.ts index cc47e0c..a9acedf 100644 --- a/ui/settings-tab.ts +++ b/ui/settings-tab.ts @@ -1,8 +1,8 @@ import { App, Notice, PluginSettingTab, Setting, setIcon } from 'obsidian'; import { ConfirmationModal } from './confirmation-modal'; import SpaceforgePlugin from '../main'; -import { ApiProvider, DEFAULT_SETTINGS, MCQQuestionAmountMode, MCQDifficulty } from '../models/settings'; -import { SpaceforgePluginData, DEFAULT_PLUGIN_STATE_DATA } from '../models/plugin-data'; +import { ApiProvider, DEFAULT_SETTINGS, MCQQuestionAmountMode, MCQDifficulty, SpaceforgeSettings } from '../models/settings'; +import { SpaceforgePluginData, DEFAULT_PLUGIN_STATE_DATA, PluginStateData } from '../models/plugin-data'; import { SM2, FSRS, POMODORO, MCQS, API, SPACEFORGE, CLAUDE, GEMINI, OLLAMA, TOGETHER_AI, WPM } from './constants'; /** @@ -37,7 +37,7 @@ export class SpaceforgeSettingTab extends PluginSettingTab { // Add a utility for creating collapsible sections const createCollapsible = (title: string, iconName: string, defaultOpen = true) => { // Create section container - const sectionContainer = containerEl.createEl('div', { cls: 'sf-settings-section' }); + const sectionContainer = containerEl.createDiv({ cls: 'sf-settings-section' }); // Create heading using Setting.setHeading() const headingSetting = new Setting(sectionContainer) @@ -46,21 +46,21 @@ export class SpaceforgeSettingTab extends PluginSettingTab { // Add icon if provided if (iconName) { - const iconEl = headingSetting.settingEl.createEl('span', { cls: 'sf-settings-icon' }); + const iconEl = headingSetting.settingEl.createSpan({ cls: 'sf-settings-icon' }); setIcon(iconEl, iconName); // Insert icon before the name headingSetting.nameEl.prepend(iconEl); } // Add collapse indicator - const collapseIndicator = headingSetting.settingEl.createEl('span', { + const collapseIndicator = headingSetting.settingEl.createSpan({ cls: 'sf-settings-collapse-indicator', text: defaultOpen ? '▾' : '▸' }); headingSetting.nameEl.appendChild(collapseIndicator); // Create content container - const contentContainer = sectionContainer.createEl('div', { + const contentContainer = sectionContainer.createDiv({ cls: 'sf-settings-section-content' }); @@ -84,7 +84,7 @@ export class SpaceforgeSettingTab extends PluginSettingTab { // Create action buttons for global data operations const createActionButtons = () => { - const actionsContainer = containerEl.createEl('div', { cls: 'sf-settings-actions' }); + const actionsContainer = containerEl.createDiv({ cls: 'sf-settings-actions' }); // Export all data button const exportBtn = actionsContainer.createEl('button', { text: 'Export all data', cls: 'sf-btn sf-btn-primary' }); @@ -178,7 +178,8 @@ export class SpaceforgeSettingTab extends PluginSettingTab { new Notice('All data imported successfully. Plugin may require a reload for all changes to take effect.'); } catch (error) { - new Notice(`Failed to import data: ${error.message} `); + const msg = error instanceof Error ? error.message : String(error); + new Notice(`Failed to import data: ${msg} `); } } }; @@ -194,8 +195,8 @@ export class SpaceforgeSettingTab extends PluginSettingTab { 'Are you sure you want to reset all plugin data (settings and state) to defaults? This cannot be undone.', async () => { // Apply default settings and default plugin state - this.plugin.settings = JSON.parse(JSON.stringify(DEFAULT_SETTINGS)); - this.plugin.pluginState = JSON.parse(JSON.stringify(DEFAULT_PLUGIN_STATE_DATA)); + this.plugin.settings = JSON.parse(JSON.stringify(DEFAULT_SETTINGS)) as SpaceforgeSettings; + this.plugin.pluginState = JSON.parse(JSON.stringify(DEFAULT_PLUGIN_STATE_DATA)) as PluginStateData; // Repopulate services with defaults this.plugin.reviewScheduleService.schedules = this.plugin.pluginState.schedules; @@ -321,7 +322,7 @@ export class SpaceforgeSettingTab extends PluginSettingTab { async () => { try { // Reset all plugin state to defaults - this.plugin.pluginState = JSON.parse(JSON.stringify(DEFAULT_PLUGIN_STATE_DATA)); + this.plugin.pluginState = JSON.parse(JSON.stringify(DEFAULT_PLUGIN_STATE_DATA)) as PluginStateData; // Update all services this.plugin.reviewScheduleService.schedules = this.plugin.pluginState.schedules; @@ -377,7 +378,7 @@ export class SpaceforgeSettingTab extends PluginSettingTab { // Changed to h3 and removed sf-settings-subsection class for potentially better contrast new Setting(spacedRepSection).setName('Algorithm configuration').setHeading(); - const algorithmContainer = spacedRepSection.createEl('div', { cls: 'sf-settings-subsection' }); // Define algorithmContainer + const algorithmContainer = spacedRepSection.createDiv({ cls: 'sf-settings-subsection' }); // Define algorithmContainer new Setting(algorithmContainer) .setName('Default scheduling algorithm') @@ -393,7 +394,7 @@ export class SpaceforgeSettingTab extends PluginSettingTab { })); // --- Dynamic "About Algorithm" Section --- - const aboutAlgoContainer = spacedRepSection.createEl('div', { cls: 'sf-info-box sf-algo-about-box' }); + const aboutAlgoContainer = spacedRepSection.createDiv({ cls: 'sf-info-box sf-algo-about-box' }); this.renderAboutAlgorithmSection(aboutAlgoContainer, this.plugin.settings.defaultSchedulingAlgorithm); // --- SM-2 Parameters --- @@ -685,10 +686,7 @@ export class SpaceforgeSettingTab extends PluginSettingTab { await this.plugin.savePluginData(); })); - interfaceSection.createEl('div', { - cls: 'sf-setting-explain', - text: `Average adults read 200-250 ${WPM} for regular content, 100-150 ${WPM} for technical content` - }); + interfaceSection.createDiv({ cls: 'sf-setting-explain', text: `Average adults read 200-250 ${WPM} for regular content, 100-150 ${WPM} for technical content` }); new Setting(interfaceSection) .setName("Navigation command") @@ -819,7 +817,7 @@ export class SpaceforgeSettingTab extends PluginSettingTab { .setName("OpenRouter configuration") .setHeading() .setClass("sf-settings-subsection-provider-header"); - const apiKeyContainer = mcqSection.createEl('div', { cls: 'sf-setting-highlight' }); + const apiKeyContainer = mcqSection.createDiv({ cls: 'sf-setting-highlight' }); new Setting(apiKeyContainer) .setName('API key') .setDesc('Required for generating MCQs via OpenRouter.') @@ -831,7 +829,7 @@ export class SpaceforgeSettingTab extends PluginSettingTab { await this.plugin.savePluginData(); })); // Removed sf-setting-explain class - apiKeyContainer.createEl('div').setText('Get your API key at https://openrouter.ai/keys'); + apiKeyContainer.createDiv().setText('Get your API key at https://openrouter.ai/keys'); new Setting(mcqSection) .setName('Model') @@ -1050,10 +1048,10 @@ export class SpaceforgeSettingTab extends PluginSettingTab { })); // Use CSS grid for the two dropdowns side by side - const mcqFormattingGrid = mcqSection.createEl('div', { cls: 'sf-setting-grid' }); + const mcqFormattingGrid = mcqSection.createDiv({ cls: 'sf-setting-grid' }); // First item in grid - const promptTypeContainer = mcqFormattingGrid.createEl('div'); + const promptTypeContainer = mcqFormattingGrid.createDiv(); new Setting(promptTypeContainer) .setName('Prompt type') .setDesc('Format for question generation') @@ -1067,7 +1065,7 @@ export class SpaceforgeSettingTab extends PluginSettingTab { })); // Second item in grid - const difficultyContainer = mcqFormattingGrid.createEl('div'); + const difficultyContainer = mcqFormattingGrid.createDiv(); new Setting(difficultyContainer) .setName('Difficulty') .setDesc('Complexity level') @@ -1124,7 +1122,7 @@ export class SpaceforgeSettingTab extends PluginSettingTab { systemPromptsContainer.createEl('summary', { text: 'System prompts (advanced)', cls: 'sf-settings-subsection' }); // Basic prompt textarea - systemPromptsContainer.createEl('div', { text: 'Basic difficulty prompt', cls: 'sf-prompt-label' }); + systemPromptsContainer.createDiv({ text: 'Basic difficulty prompt', cls: 'sf-prompt-label' }); const basicTextarea = systemPromptsContainer.createEl('textarea', { attr: { placeholder: 'Enter system prompt for basic difficulty', @@ -1141,7 +1139,7 @@ export class SpaceforgeSettingTab extends PluginSettingTab { }); // Advanced prompt textarea - systemPromptsContainer.createEl('div', { text: 'Advanced difficulty prompt', cls: 'sf-prompt-label' }); + systemPromptsContainer.createDiv({ text: 'Advanced difficulty prompt', cls: 'sf-prompt-label' }); const advancedTextarea = systemPromptsContainer.createEl('textarea', { attr: { placeholder: 'Enter system prompt for advanced difficulty', @@ -1203,7 +1201,7 @@ export class SpaceforgeSettingTab extends PluginSettingTab { } else { // If MCQ is disabled, show a message about enabling it - const mcqDisabledMessage = mcqSection.createEl('div', { cls: 'sf-info-box' }); + const mcqDisabledMessage = mcqSection.createDiv({ cls: 'sf-info-box' }); mcqDisabledMessage.createEl('p', { text: `${MCQS} are currently disabled. Enable it to configure durations and notifications.` }); @@ -1308,7 +1306,7 @@ export class SpaceforgeSettingTab extends PluginSettingTab { await this.plugin.savePluginData(); })); } else { - const pomodoroDisabledMessage = pomodoroSection.createEl('div', { cls: 'sf-info-box' }); + const pomodoroDisabledMessage = pomodoroSection.createDiv({ cls: 'sf-info-box' }); pomodoroDisabledMessage.createEl('p', { text: `${POMODORO} timer is currently disabled. Enable it to configure durations and notifications.` }); @@ -1369,7 +1367,8 @@ export class SpaceforgeSettingTab extends PluginSettingTab { new Notice('Legacy data file deleted successfully.', 3000); this.display(); // Refresh settings } catch (error) { - new Notice('Failed to delete legacy file: ' + error.message, 5000); + const msg = error instanceof Error ? error.message : String(error); + new Notice('Failed to delete legacy file: ' + msg, 5000); } } ).open(); diff --git a/ui/sidebar-view.ts b/ui/sidebar-view.ts index b761202..4b332be 100644 --- a/ui/sidebar-view.ts +++ b/ui/sidebar-view.ts @@ -56,7 +56,7 @@ export class ReviewSidebarView extends ItemView { getIcon(): string { return "calendar-clock"; } async onOpen(): Promise { - this.plugin.events.on('sidebar-update', this.refresh.bind(this)); + this.plugin.events.on('sidebar-update', () => { void this.refresh(); }); this.plugin.events.on('pomodoro-update', () => { if (this.pomodoroUIManager) { this.pomodoroUIManager.updatePomodoroUI(); @@ -71,7 +71,7 @@ export class ReviewSidebarView extends ItemView { if (this.resizeObserver) { this.resizeObserver.disconnect(); } - this.plugin.events.off('sidebar-update', this.refresh.bind(this)); + this.plugin.events.off('sidebar-update', () => { void this.refresh(); }); // No need to explicitly unregister pomodoro-update as the manager handles its own logic return Promise.resolve(); } @@ -131,7 +131,7 @@ export class ReviewSidebarView extends ItemView { setExpandedUpcomingDayKey: (key) => { this.expandedUpcomingDayKey = key; }, getLastSelectedNotePath: () => this.lastSelectedNotePath, setLastSelectedNotePath: (path) => { this.lastSelectedNotePath = path; }, - refreshSidebarView: this.refresh.bind(this) + refreshSidebarView: async () => { await this.refresh(); } }); } diff --git a/ui/sidebar/list-view-renderer.ts b/ui/sidebar/list-view-renderer.ts index 879a769..820ec2c 100644 --- a/ui/sidebar/list-view-renderer.ts +++ b/ui/sidebar/list-view-renderer.ts @@ -551,7 +551,7 @@ export class ListViewRenderer { dayItemEl.addClass("clickable"); dayItemEl.dataset.dayKey = dayKey; const daySummary = dayItemEl.createDiv("review-upcoming-day-summary"); - daySummary.createEl("span", { cls: "review-upcoming-day-name" }); // Placeholder for name + daySummary.createSpan({ cls: "review-upcoming-day-name" }); // Placeholder for name dayItemEl.addEventListener("click", (e) => { // Attach listener once const currentDayKey = (e.currentTarget as HTMLElement).dataset.dayKey; @@ -634,7 +634,7 @@ export class ListViewRenderer { this.getSelectedNotes(), lastSelectedNotePathRef, () => this.handleSelectionChange(parentContainerForBulkActions), - this.handleNoteAction.bind(this) + async () => { await this.handleNoteAction(); } ); } if (noteEl) notesInOrder.push(noteEl); @@ -680,7 +680,7 @@ export class ListViewRenderer { */ private updateSelectionClasses(container: HTMLElement): void { const selectedNotes = this.getSelectedNotes(); - const allNoteElements = container.querySelectorAll('.review-note-item[data-note-path]') as NodeListOf; + const allNoteElements = container.querySelectorAll('.review-note-item[data-note-path]'); allNoteElements.forEach(el => { const path = el.dataset.notePath; if (path && selectedNotes.includes(path)) { @@ -778,7 +778,7 @@ export class ListViewRenderer { // Find the drop target note item const target = e.target as HTMLElement; - const noteItem = target.closest('.review-note-item') as HTMLElement | null; + const noteItem = target.closest('.review-note-item'); if (!noteItem) return; @@ -966,7 +966,7 @@ export class ListViewRenderer { } headerTextEl.textContent = displayHeader; - let overdueBadge = headerTextEl.querySelector(".review-overdue-badge") as HTMLElement | null; + let overdueBadge = headerTextEl.querySelector(".review-overdue-badge"); if (dateStr === "Due notes") { const daysDiff = notesInSection.map(noteEl => { const path = (noteEl as HTMLElement).dataset.notePath; @@ -1053,7 +1053,7 @@ export class ListViewRenderer { const aIsSpecial = a in dateOrder; const bIsSpecial = b in dateOrder; - if (aIsSpecial && bIsSpecial) return dateOrder[a as keyof typeof dateOrder] - dateOrder[b as keyof typeof dateOrder]; + if (aIsSpecial && bIsSpecial) return dateOrder[a] - dateOrder[b]; if (aIsSpecial) return -1; if (bIsSpecial) return 1; diff --git a/ui/sidebar/note-item-renderer.ts b/ui/sidebar/note-item-renderer.ts index 002f0f5..7c72727 100644 --- a/ui/sidebar/note-item-renderer.ts +++ b/ui/sidebar/note-item-renderer.ts @@ -321,7 +321,7 @@ export class NoteItemRenderer { // Logic for selection (ctrl/meta/shift click) // This part uses selectedNotesArray and lastSelectedNotePathRef directly, which are passed in. // This is fine as they are managed by the calling ListViewRenderer. - const allVisibleNoteElements = Array.from(parentContainerForBulkActions.querySelectorAll('.review-note-item[data-note-path]')) as HTMLElement[]; + const allVisibleNoteElements = Array.from(parentContainerForBulkActions.querySelectorAll('.review-note-item[data-note-path]')); const allVisibleNotePaths = allVisibleNoteElements.map(el => el.dataset.notePath).filter(p => p) as string[]; const currentIndex = allVisibleNotePaths.indexOf(currentPath); @@ -335,7 +335,7 @@ export class NoteItemRenderer { notesToSelectInRange.forEach(p => { if (p && !selectedNotesArray.includes(p)) selectedNotesArray.push(p); }); } else { selectedNotesArray.length = 0; - selectedNotesArray.push(...notesToSelectInRange.filter(p => p) as string[]); + selectedNotesArray.push(...notesToSelectInRange.filter(p => p)); } } else { selectedNotesArray.length = 0; diff --git a/utils/event-emitter.ts b/utils/event-emitter.ts index 78ac38b..07dcaec 100644 --- a/utils/event-emitter.ts +++ b/utils/event-emitter.ts @@ -3,7 +3,7 @@ */ export type EventMap = Record; -export class EventEmitter> { +export class EventEmitter> { /** * Event listeners by event name */ diff --git a/versions.json b/versions.json index 1d7eb49..0486b47 100644 --- a/versions.json +++ b/versions.json @@ -3,5 +3,6 @@ "1.0.1": "0.15.0", "1.0.2": "0.15.0", "1.0.3": "0.15.0", + "1.0.5": "1.8.7", "1.0.4": "0.15.0" } \ No newline at end of file