feat: notes in lesson

This commit is contained in:
Jannat Patel
2025-08-05 20:00:09 +05:30
parent 2271eb270e
commit 77ecb02a17
18 changed files with 1237 additions and 1789 deletions

View File

@@ -1,5 +1,6 @@
import { call, toast } from 'frappe-ui'
import { useTimeAgo } from '@vueuse/core'
import { theme } from '@/utils/theme'
import { Quiz } from '@/utils/quiz'
import { Program } from '@/utils/program'
import { Assignment } from '@/utils/assignment'
@@ -673,3 +674,97 @@ export const convertToMinutes = (seconds) => {
const remainingSeconds = Math.round(seconds % 60)
return `${minutes}:${remainingSeconds.toString().padStart(2, '0')}`
}
const getRootNode = (selector = '#editor') => {
const root = document.querySelector(selector)
if (!root) {
console.warn(`Root node not found for selector: ${selector}`)
}
return root
}
const createTextWalker = (root, phrase) => {
return document.createTreeWalker(root, NodeFilter.SHOW_TEXT, {
acceptNode(node) {
return node.nodeValue.toLowerCase().includes(phrase.toLowerCase())
? NodeFilter.FILTER_ACCEPT
: NodeFilter.FILTER_SKIP
},
})
}
const findMatchingTextNode = (walker, phrase) => {
const node = walker.nextNode()
if (!node) return null
const startIndex = node.nodeValue
.toLowerCase()
.indexOf(phrase.toLowerCase())
const endIndex = startIndex + phrase.length
return { node, startIndex, endIndex }
}
const createHighlightSpan = (color, name) => {
const span = document.createElement('span')
span.className = 'highlighted-text'
span.style.backgroundColor = theme.backgroundColor[color][200]
span.dataset.name = name
return span
}
const wrapRangeInHighlight = ({ node, startIndex, endIndex }, color, name) => {
const range = document.createRange()
range.setStart(node, startIndex)
range.setEnd(node, endIndex)
const span = createHighlightSpan(color, name)
range.surroundContents(span)
}
export const highlightText = (note, scrollIntoView = false) => {
if (!note?.highlighted_text) return
const root = getRootNode()
if (!root) return
const phrase = note.highlighted_text
const color = note.color.toLowerCase()
const walker = createTextWalker(root, phrase)
const match = findMatchingTextNode(walker, phrase)
if (!match) return
wrapRangeInHighlight(match, color, note.name)
if (scrollIntoView) {
match.node.parentElement.scrollIntoView({
behavior: 'smooth',
block: 'center',
})
setTimeout(() => {
const highlightedElements =
document.querySelectorAll('.highlighted-text')
highlightedElements.forEach((el) => {
if (el.dataset.name === note.name) {
el.style.backgroundColor = 'transparent'
}
})
}, 3000)
}
}
export const scrollToReference = (text) => {
highlightText({ highlighted_text: text, color: 'yellow', name: '' }, true)
}
export const blockQuotesClick = () => {
document.querySelectorAll('blockquote').forEach((el) => {
el.addEventListener('click', (e) => {
const text = e.target.textContent || ''
if (text) {
scrollToReference(text)
}
})
})
}