mirror of
https://github.com/peritus/obsidian-interactive-ratings.git
synced 2026-07-22 05:43:17 +00:00
145 lines
No EOL
4.3 KiB
TypeScript
145 lines
No EOL
4.3 KiB
TypeScript
// Global logging control
|
|
export const LOGGING_ENABLED = true;
|
|
|
|
export function getUnicodeCharLength(str: string): number {
|
|
return [...str].length;
|
|
}
|
|
|
|
export function getUnicodeSubstring(str: string, start: number, end: number): string {
|
|
return [...str].slice(start, end).join('');
|
|
}
|
|
|
|
// Extract rating calculation from the click handler
|
|
export function calculateNewRating(overlay: HTMLElement, clientX: number): number {
|
|
const containerRect = overlay.getBoundingClientRect();
|
|
const symbolCount = parseInt(overlay.dataset.symbolCount);
|
|
const symbolWidth = containerRect.width / symbolCount;
|
|
const relativeX = clientX - containerRect.left;
|
|
const hoveredSymbolIndex = Math.floor(relativeX / symbolWidth);
|
|
const positionWithinSymbol = (relativeX % symbolWidth) / symbolWidth;
|
|
|
|
// Determine if we should use half symbol or full symbol
|
|
const supportsHalf = overlay.dataset.supportsHalf === 'true';
|
|
const useHalfSymbol = supportsHalf && positionWithinSymbol < 0.5;
|
|
|
|
// Calculate rating
|
|
let newRating = hoveredSymbolIndex + (useHalfSymbol ? 0.5 : 1);
|
|
if (newRating < 0) {
|
|
newRating = 0;
|
|
}
|
|
|
|
if (LOGGING_ENABLED) {
|
|
console.debug(`[InteractiveRatings] Calculated new rating`, {
|
|
clientX,
|
|
containerRect: {
|
|
left: containerRect.left,
|
|
width: containerRect.width
|
|
},
|
|
symbolCount,
|
|
symbolWidth,
|
|
relativeX,
|
|
hoveredSymbolIndex,
|
|
positionWithinSymbol,
|
|
supportsHalf,
|
|
useHalfSymbol,
|
|
newRating
|
|
});
|
|
}
|
|
|
|
return newRating;
|
|
}
|
|
|
|
// Extract the function to generate new symbol string
|
|
export function generateSymbolsString(rating, symbolCount, full, empty, half, supportsHalf) {
|
|
let newSymbols = '';
|
|
|
|
for (let i = 0; i < symbolCount; i++) {
|
|
if (i < Math.floor(rating)) {
|
|
newSymbols += full;
|
|
} else if (supportsHalf && i === Math.floor(rating) && rating % 1 !== 0) {
|
|
newSymbols += half;
|
|
} else {
|
|
newSymbols += empty;
|
|
}
|
|
}
|
|
|
|
if (LOGGING_ENABLED) {
|
|
console.debug(`[InteractiveRatings] Generated symbols string`, {
|
|
rating,
|
|
symbolCount,
|
|
full,
|
|
empty,
|
|
half,
|
|
supportsHalf,
|
|
newSymbols
|
|
});
|
|
};
|
|
|
|
return newSymbols;
|
|
}
|
|
|
|
// Extract the function to format rating text
|
|
export function formatRatingText(format, newRating, symbolCount, denominator, supportsHalf: boolean) {
|
|
let newNumerator;
|
|
if (format.includes('percent')) {
|
|
newNumerator = Math.round((newRating / symbolCount) * 100);
|
|
} else {
|
|
newNumerator = newRating;
|
|
if (!supportsHalf) {
|
|
newNumerator = Math.round(newNumerator);
|
|
}
|
|
}
|
|
|
|
// Format the text based on the original format
|
|
let formattedText = '';
|
|
switch (format) {
|
|
case 'fraction':
|
|
formattedText = ` ${newNumerator}/${denominator}`;
|
|
break;
|
|
case 'fraction-parentheses':
|
|
formattedText = ` (${newNumerator}/${denominator})`;
|
|
break;
|
|
case 'percent':
|
|
formattedText = ` ${newNumerator}%`;
|
|
break;
|
|
case 'percent-parentheses':
|
|
formattedText = ` (${newNumerator}%)`;
|
|
break;
|
|
default:
|
|
formattedText = '';
|
|
}
|
|
|
|
if (LOGGING_ENABLED) {
|
|
console.debug(`[InteractiveRatings] Formatted rating text`, {
|
|
format,
|
|
newRating,
|
|
symbolCount,
|
|
denominator,
|
|
supportsHalf,
|
|
newNumerator,
|
|
formattedText
|
|
});
|
|
};
|
|
|
|
return formattedText;
|
|
}
|
|
|
|
// Define symbol patterns as a global constant
|
|
export const SYMBOL_PATTERNS = [
|
|
{ full: '★', empty: '☆', half: null }, // Symbols
|
|
{ full: '●', empty: '○', half: '◐' }, // Circles
|
|
{ full: '■', empty: '□', half: '◧' }, // Squares
|
|
{ full: '▲', empty: '△', half: null }, // Triangles (no half)
|
|
|
|
// Progress bar patterns
|
|
{ full: '█', empty: '▁', half: null }, // Block progress
|
|
{ full: '⣿', empty: '⣀', half: '⡇' }, // Braille dots
|
|
{ full: '⬤', empty: '○', half: null }, // Solid/empty circles
|
|
{ full: '■', empty: '□', half: null }, // Solid/empty squares
|
|
{ full: '▰', empty: '▱', half: null }, // Dotted squares
|
|
{ full: '◼', empty: '▭', half: null }, // Filled/empty rectangles
|
|
{ full: '▮', empty: '▯', half: null }, // Vertical bars
|
|
{ full: '⬤', empty: '◯', half: null }, // Bold circles
|
|
{ full: '⚫', empty: '⚪', half: null }, // Black/white circles
|
|
{ full: '█', empty: '░', half: null }, // Block/light shade
|
|
]; |