)}
@@ -181,62 +405,109 @@ export default function CitationCard({ event, className, displayType = 'end' }:
{citationData.version && (
+ {t('Open Timestamp')}: {citationData.openTimestamp}
+
)
} else if (citationData.type === 'hardcopy') {
+ // Display ALL hardcopy fields - show everything that exists
+ // Debug: Log all fields to see what we have
+ console.log('Hardcopy citation data:', {
+ author: citationData.author,
+ title: citationData.title,
+ chapterTitle: citationData.chapterTitle,
+ editor: citationData.editor,
+ publishedIn: citationData.publishedIn,
+ volume: citationData.volume,
+ publishedBy: citationData.publishedBy,
+ publishedOn: citationData.publishedOn,
+ pageRange: citationData.pageRange,
+ doi: citationData.doi,
+ accessedOn: citationData.accessedOn,
+ version: citationData.version,
+ location: citationData.location,
+ geohash: citationData.geohash,
+ summary: citationData.summary,
+ content: event.content,
+ allTags: event.tags
+ })
+
return (
- {citationData.author && (
+ {citationData.author && citationData.author.trim() !== '' && (
{citationData.author}
)}
- {citationData.title && (
+ {citationData.title && citationData.title.trim() !== '' && (
"{citationData.title}"
)}
- {citationData.chapterTitle && (
+ {citationData.chapterTitle && citationData.chapterTitle.trim() !== '' && (
{t('Chapter')}: {citationData.chapterTitle}
)}
- {citationData.editor && (
+ {citationData.editor && citationData.editor.trim() !== '' && (
{t('Edited by')} {citationData.editor}
)}
- {citationData.publishedIn && (
+ {citationData.publishedIn && citationData.publishedIn.trim() !== '' && (
{t('Published in')} {citationData.publishedIn}
- {citationData.volume && `, ${t('Volume')} ${citationData.volume}`}
+ {citationData.volume && citationData.volume.trim() !== '' ? `, ${t('Volume')} ${citationData.volume}` : ''}
)}
- {citationData.publishedBy && (
+ {citationData.publishedBy && citationData.publishedBy.trim() !== '' && (
{citationData.publishedBy}
)}
- {citationData.publishedOn && (
-
{formatDate(citationData.publishedOn)}
+ {citationData.publishedOn && citationData.publishedOn.trim() !== '' && (
+
{t('Published on')} {formatDate(citationData.publishedOn)}
)}
- {citationData.pageRange && (
+ {citationData.pageRange && citationData.pageRange.trim() !== '' && (
{t('Pages')}: {citationData.pageRange}
)}
- {citationData.doi && (
+ {citationData.doi && citationData.doi.trim() !== '' && (
DOI: {citationData.doi}
)}
- {citationData.accessedOn && (
+ {citationData.accessedOn && citationData.accessedOn.trim() !== '' && (
{t('Accessed on')} {formatDate(citationData.accessedOn)}
)}
- {citationData.version && (
+ {citationData.version && citationData.version.trim() !== '' && (
{t('Version')}: {citationData.version}
)}
- {citationData.summary && (
-
{citationData.summary}
+ {citationData.location && citationData.location.trim() !== '' && (
+
+ {t('Location')}: {citationData.location}
+
)}
- {event.content && (
-
+ {citationData.geohash && citationData.geohash.trim() !== '' && (
+
+ {t('Geohash')}: {citationData.geohash}
+
+ )}
+ {citationData.summary && citationData.summary.trim() !== '' && (
+
{citationData.summary}
+ )}
+ {event.content && event.content.trim() !== '' && (
+
{event.content}
)}
@@ -263,10 +534,10 @@ export default function CitationCard({ event, className, displayType = 'end' }:
)}
{citationData.summary && (
-
{citationData.summary}
+
{citationData.summary}
)}
{event.content && (
-
+
{event.content}
)}
@@ -277,42 +548,24 @@ export default function CitationCard({ event, className, displayType = 'end' }:
return null
}
- const getIcon = () => {
- switch (citationData.type) {
- case 'internal':
- return
- case 'external':
- return
- case 'hardcopy':
- return
- case 'prompt':
- return
- default:
- return
- }
- }
-
- const getTitle = () => {
- switch (citationData.type) {
- case 'internal':
- return t('Internal Citation')
- case 'external':
- return t('External Citation')
- case 'hardcopy':
- return t('Hardcopy Citation')
- case 'prompt':
- return t('Prompt Citation')
- default:
- return t('Citation')
- }
- }
- // For inline citations, render a compact version
+ // For inline citations, render a compact version in academic format
if (displayType === 'inline' || displayType === 'prompt-inline') {
- const inlineText = citationData.type === 'internal' && citationData.author && citationData.publishedOn
- ? `(${citationData.author}, ${formatDate(citationData.publishedOn)})`
- : citationData.type === 'prompt' && citationData.llm
- ? `(${citationData.llm})`
+ // APA format: (Author, Year)
+ const author = citationData.type === 'internal' || citationData.type === 'external' || citationData.type === 'hardcopy'
+ ? citationData.author
+ : citationData.type === 'prompt'
+ ? citationData.llm
+ : ''
+
+ const year = formatYear(
+ citationData.publishedOn || citationData.accessedOn || ''
+ )
+
+ const inlineText = author && year
+ ? `(${author}, ${year})`
+ : author
+ ? `(${author})`
: `[${t('Citation')}]`
return (
@@ -335,55 +588,59 @@ export default function CitationCard({ event, className, displayType = 'end' }:
)
}
- // For footnotes (foot-end), render a brief reference
+ // For footnotes (foot-end), render a brief academic reference
if (displayType === 'foot-end') {
+ const academicText = formatAcademicCitation()
+ return (
+
+
+ {academicText || t('See reference')}
+
+
+ )
+ }
+
+ // For footnotes (foot), render full citation information (same as endnotes)
+ if (displayType === 'foot') {
+ return (
+
+
+ {renderCitationContent()}
+
+
+ )
+ }
+
+ // For endnotes and prompt-end, render full citation information (no card UI)
+ if (displayType === 'end' || displayType === 'prompt-end') {
return (
-
- {citationData.type === 'internal' && citationData.author && citationData.publishedOn
- ? `${citationData.author}, ${formatDate(citationData.publishedOn)}`
- : citationData.type === 'external' && citationData.author
- ? `${citationData.author}`
- : citationData.type === 'hardcopy' && citationData.author
- ? `${citationData.author}`
- : citationData.type === 'prompt' && citationData.llm
- ? `${citationData.llm}`
- : t('See reference')}
+
+ {renderCitationContent()}
)
}
- // For quotes, render with quote styling
+ // For quotes (block-level), render full citation information in block quote format
if (displayType === 'quote') {
return (
-
-
-
- {getIcon()}
- {getTitle()}
-
-
-
+
+
{renderCitationContent()}
-
-
+
+
)
}
- // For endnotes, footnotes, and prompt-end, render full citation
+ // Default: render in academic format
+ const academicText = formatAcademicCitation()
return (
-
-
-
- {getIcon()}
- {getTitle()}
-
-
-
- {renderCitationContent()}
-
-
+
+
+ {academicText || t('Citation')}
+
+
)
}
diff --git a/src/components/EmbeddedCitation/index.tsx b/src/components/EmbeddedCitation/index.tsx
index 371ba44..84de6aa 100644
--- a/src/components/EmbeddedCitation/index.tsx
+++ b/src/components/EmbeddedCitation/index.tsx
@@ -55,6 +55,6 @@ export default function EmbeddedCitation({ citationId, displayType = 'end', clas
)
}
- return
+ return
}
diff --git a/src/components/Note/AsciidocArticle/AsciidocArticle.tsx b/src/components/Note/AsciidocArticle/AsciidocArticle.tsx
index 64404d7..479bc01 100644
--- a/src/components/Note/AsciidocArticle/AsciidocArticle.tsx
+++ b/src/components/Note/AsciidocArticle/AsciidocArticle.tsx
@@ -1223,26 +1223,26 @@ export default function AsciidocArticle({
footnotesSection.appendChild(h3)
const ol = document.createElement('ol')
- ol.className = 'list-decimal list-inside space-y-2'
+ // Academic style: proper list formatting with aligned numbers
+ ol.className = 'list-decimal pl-6 space-y-3'
+ ol.style.listStylePosition = 'outside'
footnotes.forEach((citation) => {
const li = document.createElement('li')
li.id = citation.id
- li.className = 'text-sm'
-
- const span = document.createElement('span')
- span.className = 'font-semibold'
- span.textContent = `[${citation.index + 1}]: `
- li.appendChild(span)
+ li.className = 'text-sm pl-2'
+ li.style.display = 'list-item'
const citationContainer = document.createElement('span')
- citationContainer.className = 'inline-block mt-1'
+ citationContainer.className = 'inline'
li.appendChild(citationContainer)
const backLink = document.createElement('a')
backLink.href = `#citation-ref-${citation.index}`
- backLink.className = 'text-green-600 dark:text-green-400 hover:text-green-700 dark:hover:text-green-300 hover:underline text-xs ml-1'
- backLink.textContent = '↩'
+ backLink.className = 'text-green-600 dark:text-green-400 hover:text-green-700 dark:hover:text-green-300 hover:underline text-xs ml-2 inline-flex items-center'
+ backLink.setAttribute('aria-label', 'Return to citation')
+ // Use hyperlink icon instead of emoji
+ backLink.innerHTML = ' '
backLink.addEventListener('click', (e) => {
e.preventDefault()
const refElement = document.getElementById(`citation-ref-${citation.index}`)
@@ -1254,8 +1254,13 @@ export default function AsciidocArticle({
ol.appendChild(li)
- // Render citation component
- const citationRoot = createRoot(citationContainer)
+ // Render citation component - use a wrapper div to position backlink
+ const citationWrapperDiv = document.createElement('div')
+ citationWrapperDiv.className = 'inline'
+ citationWrapperDiv.style.display = 'inline'
+ citationContainer.appendChild(citationWrapperDiv)
+
+ const citationRoot = createRoot(citationWrapperDiv)
citationRoot.render(
@@ -1266,7 +1271,22 @@ export default function AsciidocArticle({
)
- reactRootsRef.current.set(citationContainer, citationRoot)
+ reactRootsRef.current.set(citationWrapperDiv, citationRoot)
+
+ // Insert backlink at end of first line after citation renders
+ setTimeout(() => {
+ const firstDiv = citationWrapperDiv.querySelector('div:first-child') as HTMLElement
+ if (firstDiv) {
+ firstDiv.style.display = 'inline'
+ firstDiv.style.position = 'relative'
+ backLink.style.position = 'absolute'
+ backLink.style.right = '0'
+ backLink.style.top = '0'
+ firstDiv.appendChild(backLink)
+ } else {
+ citationWrapperDiv.appendChild(backLink)
+ }
+ }, 100)
})
footnotesSection.appendChild(ol)
@@ -1298,26 +1318,29 @@ export default function AsciidocArticle({
referencesSection.appendChild(h3)
const ol = document.createElement('ol')
- ol.className = 'list-decimal list-inside space-y-2'
+ // Academic style: proper list formatting with aligned numbers
+ ol.className = 'list-decimal pl-6 space-y-3'
+ ol.style.listStylePosition = 'outside'
endCitations.forEach((citation) => {
const li = document.createElement('li')
li.id = `citation-end-${citation.index}`
- li.className = 'text-sm'
+ li.className = 'text-sm pl-2'
+ li.style.display = 'list-item'
- const span = document.createElement('span')
- span.className = 'font-semibold'
- span.textContent = `[${citation.index + 1}]: `
- li.appendChild(span)
+ const citationWrapper = document.createElement('div')
+ citationWrapper.className = 'inline-block w-full relative'
+ li.appendChild(citationWrapper)
const citationContainer = document.createElement('span')
- citationContainer.className = 'inline-block mt-1'
- li.appendChild(citationContainer)
+ citationContainer.className = 'inline'
+ citationWrapper.appendChild(citationContainer)
const backLink = document.createElement('a')
backLink.href = `#citation-ref-${citation.index}`
- backLink.className = 'text-green-600 dark:text-green-400 hover:text-green-700 dark:hover:text-green-300 hover:underline text-xs ml-1'
- backLink.textContent = '↩'
+ backLink.className = 'text-green-600 dark:text-green-400 hover:text-green-700 dark:hover:text-green-300 hover:underline text-xs ml-2 inline-flex items-center'
+ backLink.setAttribute('aria-label', 'Return to citation')
+ backLink.innerHTML = ' '
backLink.addEventListener('click', (e) => {
e.preventDefault()
const refElement = document.getElementById(`citation-ref-${citation.index}`)
@@ -1325,7 +1348,6 @@ export default function AsciidocArticle({
refElement.scrollIntoView({ behavior: 'smooth', block: 'center' })
}
})
- li.appendChild(backLink)
ol.appendChild(li)
@@ -1342,6 +1364,21 @@ export default function AsciidocArticle({
)
reactRootsRef.current.set(citationContainer, citationRoot)
+
+ // Insert backlink at end of first line after citation renders
+ setTimeout(() => {
+ const firstDiv = citationContainer.querySelector('div:first-child') as HTMLElement
+ if (firstDiv) {
+ firstDiv.style.display = 'inline'
+ firstDiv.style.position = 'relative'
+ backLink.style.position = 'absolute'
+ backLink.style.right = '0'
+ backLink.style.top = '0'
+ firstDiv.appendChild(backLink)
+ } else {
+ citationWrapper.appendChild(backLink)
+ }
+ }, 100)
})
referencesSection.appendChild(ol)
@@ -1778,6 +1815,38 @@ export default function AsciidocArticle({
font-size: 0.83em;
line-height: 0;
}
+ /* Academic references section formatting */
+ .asciidoc-content #references-section ol,
+ .asciidoc-content #footnotes-section ol {
+ list-style: decimal;
+ padding-left: 1.5rem;
+ list-style-position: outside;
+ }
+ .asciidoc-content #references-section li,
+ .asciidoc-content #footnotes-section li {
+ padding-left: 0.5rem;
+ margin-bottom: 0.5rem;
+ line-height: 1.6;
+ display: list-item;
+ }
+ /* Position backlink at end of first line */
+ .asciidoc-content #references-section li > div > span > div:first-child,
+ .asciidoc-content #footnotes-section li > div > span > div:first-child {
+ position: relative;
+ display: inline-block;
+ width: 100%;
+ }
+ .asciidoc-content #references-section h3,
+ .asciidoc-content #footnotes-section h3 {
+ font-size: 1.125rem;
+ font-weight: 600;
+ margin-bottom: 1rem;
+ }
+ /* Blockquote spacing in citations */
+ .asciidoc-content #references-section blockquote,
+ .asciidoc-content #footnotes-section blockquote {
+ padding-left: 1.5rem !important;
+ }
`}
{/* Metadata */}
diff --git a/src/components/Note/MarkdownArticle/MarkdownArticle.tsx b/src/components/Note/MarkdownArticle/MarkdownArticle.tsx
index e0d2f7b..7aadd55 100644
--- a/src/components/Note/MarkdownArticle/MarkdownArticle.tsx
+++ b/src/components/Note/MarkdownArticle/MarkdownArticle.tsx
@@ -2509,33 +2509,36 @@ function parseMarkdownContent(
wrappedParts.push(
Citations
-
+
{footCitations.map((citation, idx) => (
- [{idx + 1}]: {' '}
-
- {' '}
- {
- e.preventDefault()
- const refElement = document.getElementById(`citation-ref-${citation.id.replace('citation-', '')}`)
- if (refElement) {
- refElement.scrollIntoView({ behavior: 'smooth', block: 'center' })
- }
- }}
- >
- ↩
-
+
))}
@@ -2549,33 +2552,37 @@ function parseMarkdownContent(
wrappedParts.push(
References
-
+
{endCitations.map((citation, idx) => (
- [{idx + 1}]: {' '}
-
- {' '}
- {
- e.preventDefault()
- const refElement = document.getElementById(`citation-ref-${citation.id.replace('citation-', '')}`)
- if (refElement) {
- refElement.scrollIntoView({ behavior: 'smooth', block: 'center' })
- }
- }}
- >
- ↩
-
+
))}
diff --git a/src/components/PostEditor/PostContent.tsx b/src/components/PostEditor/PostContent.tsx
index ed6aade..3f632dc 100644
--- a/src/components/PostEditor/PostContent.tsx
+++ b/src/components/PostEditor/PostContent.tsx
@@ -580,14 +580,26 @@ export default function PostContent({
summary: citationSummary.trim() || undefined
})
} else if (isCitationHardcopy) {
- return createCitationHardcopyDraftEvent(cleanedText, {
- accessedOn: citationAccessedOn.trim() || new Date().toISOString(),
+ // Convert date strings to ISO 8601 format if they exist
+ const formatDateToISO = (dateStr: string): string => {
+ if (!dateStr || !dateStr.trim()) return ''
+ // If already in ISO format, return as is
+ if (dateStr.includes('T')) return dateStr
+ // If in YYYY-MM-DD format, convert to ISO
+ if (dateStr.match(/^\d{4}-\d{2}-\d{2}$/)) {
+ return new Date(dateStr + 'T00:00:00Z').toISOString()
+ }
+ return dateStr
+ }
+
+ const hardcopyOptions = {
+ accessedOn: formatDateToISO(citationAccessedOn.trim()) || new Date().toISOString(),
title: citationTitle.trim() || undefined,
author: citationAuthor.trim() || undefined,
pageRange: citationHardcopyPageRange.trim() || undefined,
chapterTitle: citationHardcopyChapterTitle.trim() || undefined,
editor: citationHardcopyEditor.trim() || undefined,
- publishedOn: citationPublishedOn.trim() || undefined,
+ publishedOn: citationPublishedOn.trim() ? formatDateToISO(citationPublishedOn.trim()) : undefined,
publishedBy: citationPublishedBy.trim() || undefined,
publishedIn: citationHardcopyPublishedIn.trim() || undefined,
volume: citationHardcopyVolume.trim() || undefined,
@@ -596,7 +608,12 @@ export default function PostContent({
location: citationLocation.trim() || undefined,
geohash: citationGeohash.trim() || undefined,
summary: citationSummary.trim() || undefined
- })
+ }
+
+ // Debug: Log what we're passing to the function
+ console.log('Creating hardcopy citation with options:', hardcopyOptions)
+
+ return createCitationHardcopyDraftEvent(cleanedText, hardcopyOptions)
} else if (isCitationPrompt) {
return createCitationPromptDraftEvent(cleanedText, {
llm: citationPromptLlm.trim(),
@@ -1641,13 +1658,14 @@ export default function PostContent({
{/* Citation metadata fields */}
{(isCitationInternal || isCitationExternal || isCitationHardcopy || isCitationPrompt) && (
-
+
{isCitationInternal && t('Internal Citation Settings')}
{isCitationExternal && t('External Citation Settings')}
{isCitationHardcopy && t('Hardcopy Citation Settings')}
{isCitationPrompt && t('Prompt Citation Settings')}
+
{/* Prompt Citation specific fields - shown first if prompt */}
{isCitationPrompt && (
@@ -1939,8 +1957,8 @@ export default function PostContent({
/>
- {/* Summary field - different label for prompt citations */}
-
+ {/* Summary field - different label for prompt citations - spans full width on desktop */}
+
{isCitationPrompt ? t('Prompt Conversation Script') : t('Summary')}
@@ -1981,6 +1999,7 @@ export default function PostContent({
>
)}
+
)}