diff --git a/components/text.js b/components/text.js index 36b06cf0e..757a568e5 100644 --- a/components/text.js +++ b/components/text.js @@ -255,7 +255,7 @@ function P ({ children, node, onlyImages, somethingBefore, somethingAfter, ...pr ) } -function Details({ children, node, ...props }) { +function Details ({ children, node, ...props }) { return (
{children} @@ -263,7 +263,7 @@ function Details({ children, node, ...props }) { ) } -function Summary({ children, node, ...props }) { +function Summary ({ children, node, ...props }) { return ( {children} diff --git a/components/text.module.css b/components/text.module.css index b526da1ac..7b5dc2fd8 100644 --- a/components/text.module.css +++ b/components/text.module.css @@ -439,3 +439,42 @@ } /* Details/Summary styling */ +.details { + border-left: 2px solid var(--theme-quoteBar); + padding-left: 0.75rem; + margin: calc(var(--grid-gap) * 0.5) 0; + transition: border-color 0.2s ease; +} + +.details[open] { + border-left-color: #f7931a; +} + +.summary { + cursor: pointer; + user-select: none; + color: #8b949e; + transition: color 0.2s ease; + padding: 0.25rem 0; +} + +.summary:hover { + color: #ffd700; +} + + +.summary::marker, +.summary::-webkit-details-marker { + color: #8b949e; +} + +.details[open] > .summary::marker, +.details[open] > .summary::-webkit-details-marker { + color: #f7931a; +} + + +.details > *:not(.summary) { + margin-top: calc(var(--grid-gap) * 0.5); + padding-bottom: calc(var(--grid-gap) * 0.25); +} diff --git a/lib/rehype-sn.js b/lib/rehype-sn.js index 43290478d..6ee4241ab 100644 --- a/lib/rehype-sn.js +++ b/lib/rehype-sn.js @@ -13,14 +13,13 @@ const mentionRegex = new RegExp('@(' + userGroup + '(?:\\/' + userGroup + ')?)', const subRegex = new RegExp('~(' + subGroup + '(?:\\/' + subGroup + ')?)', 'gi') const nostrIdRegex = /\b((npub1|nevent1|nprofile1|note1|naddr1)[02-9ac-hj-np-z]+)\b/g -export default function rehypeSN(options = {}) { +export default function rehypeSN (options = {}) { const { stylers = [] } = options - return function transformer(tree) { + return function transformer (tree) { try { visit(tree, (node, index, parent) => { - - // Leave all other existing handlers unchanged + // Handle inline code property if (node.tagName === 'code') { node.properties.inline = !(parent && parent.tagName === 'pre') } @@ -233,7 +232,7 @@ export default function rehypeSN(options = {}) { // Handle self-contained details block if (node.value.includes('
')) { let content = node.value - + // Extract summary if present const summaryMatch = content.match(/(.*?)<\/summary>/s) if (summaryMatch) { @@ -244,13 +243,13 @@ export default function rehypeSN(options = {}) { detailsContent.summary.complete = true content = content.replace(/.*?<\/summary>/s, '') } - + // Clean remaining content const cleanedContent = content .replace(/
/g, '') .replace(/<\/details>/g, '') .trim() - + if (cleanedContent) { detailsContent.content.push({ type: 'text', @@ -263,7 +262,7 @@ export default function rehypeSN(options = {}) { // Clean opening details tag and handle potential summary let cleanedContent = node.value.replace(/
/g, '') - + // Check for summary in opening node const summaryMatch = cleanedContent.match(/(.*?)<\/summary>/s) if (summaryMatch) { @@ -274,7 +273,7 @@ export default function rehypeSN(options = {}) { detailsContent.summary.complete = true cleanedContent = cleanedContent.replace(/.*?<\/summary>/s, '') } - + if (cleanedContent.trim()) { detailsContent.content.push({ type: 'text', @@ -285,11 +284,11 @@ export default function rehypeSN(options = {}) { // Collect remaining content let currentIndex = index let foundClosing = false - + while (currentIndex < parent.children.length) { const currentNode = parent.children[++currentIndex] if (!currentNode) break - + // Handle summary tags if we haven't found a complete summary yet if (!detailsContent.summary.complete) { if (currentNode.type === 'raw' && currentNode.value.includes('')) { @@ -316,7 +315,7 @@ export default function rehypeSN(options = {}) { const afterSummary = currentNode.value.substring( currentNode.value.indexOf('') + ''.length ).trim() - + if (afterSummary) { detailsContent.content.push({ type: 'text', @@ -335,7 +334,7 @@ export default function rehypeSN(options = {}) { } continue } - + // If we're collecting summary content if (detailsContent.summary.found) { if (currentNode.type === 'raw' && currentNode.value.includes('')) { @@ -360,9 +359,8 @@ export default function rehypeSN(options = {}) { // Check for closing details tag const hasClosingTag = (currentNode.type === 'raw' && currentNode.value.includes('
')) || (currentNode.type === 'element' && toString(currentNode).includes('
')) - + if (hasClosingTag) { - let cleanedContent if (currentNode.type === 'raw') { const textBeforeClosing = currentNode.value.substring(0, currentNode.value.indexOf('')) if (textBeforeClosing.includes('\n')) { @@ -418,18 +416,17 @@ export default function rehypeSN(options = {}) { return createDetailsElement(detailsContent, parent, index) } - }) return tree } catch (error) { - console.error('❌ Error in rehypeSN transformer:', error) + console.error('Error in rehypeSN transformer:', error) return tree } } } -function isImageOnlyParagraph(node) { +function isImageOnlyParagraph (node) { return node && node.tagName === 'p' && Array.isArray(node.children) && @@ -439,7 +436,7 @@ function isImageOnlyParagraph(node) { ) } -function replaceMention(value, username) { +function replaceMention (value, username) { return { type: 'element', tagName: 'mention', @@ -448,7 +445,7 @@ function replaceMention(value, username) { } } -function replaceSub(value, sub) { +function replaceSub (value, sub) { return { type: 'element', tagName: 'sub', @@ -457,7 +454,7 @@ function replaceSub(value, sub) { } } -function replaceNostrId(value, id) { +function replaceNostrId (value, id) { return { type: 'element', tagName: 'a', @@ -466,7 +463,7 @@ function replaceNostrId(value, id) { } } -function isMisleadingLink(text, href) { +function isMisleadingLink (text, href) { let misleading = false if (/^\s*(\w+\.)+\w+/.test(text)) { @@ -482,12 +479,7 @@ function isMisleadingLink(text, href) { } // Helper to create details element -function createDetailsElement(detailsContent, parent, index) { - console.log('\n🔨 Creating details element with:', { - hasSummary: detailsContent.summary.complete, - contentNodes: detailsContent.content.length - }) - +function createDetailsElement (detailsContent, parent, index) { const detailsElement = { type: 'element', tagName: 'details', @@ -504,12 +496,10 @@ function createDetailsElement(detailsContent, parent, index) { children: detailsContent.summary.content } detailsElement.children.push(summaryElement) - console.log('✨ Added summary element') } // Add main content detailsElement.children.push(...detailsContent.content) - console.log('✨ Added content elements') // Replace nodes parent.children.splice(