Skip to content

Commit df73601

Browse files
journals link to pages
1 parent 22c5344 commit df73601

File tree

2 files changed

+186
-1
lines changed

2 files changed

+186
-1
lines changed

journals.html

Lines changed: 177 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,28 @@
370370
justify-content: space-between;
371371
}
372372
}
373+
374+
.wiki-link {
375+
color: var(--primary);
376+
text-decoration: none;
377+
border-bottom: 1px dashed var(--primary-light);
378+
cursor: pointer;
379+
}
380+
381+
.wiki-link:hover {
382+
background-color: rgba(0, 130, 201, 0.1);
383+
border-bottom: 1px solid var(--primary);
384+
}
385+
386+
/* Add a special style for non-existent pages */
387+
.wiki-link.new-page {
388+
color: #e67e22;
389+
border-bottom: 1px dashed #e67e22;
390+
}
391+
392+
.wiki-link.new-page:hover {
393+
background-color: rgba(230, 126, 34, 0.1);
394+
}
373395
</style>
374396
</head>
375397
<body>
@@ -393,6 +415,38 @@
393415
// Make secp256k1 available globally (required by nosdav-shim.js)
394416
window.secp256k1 = secp256k1
395417

418+
// Configure Marked to recognize wiki-links [[foo]]
419+
const wikiLinkExtension = {
420+
name: 'wikiLink',
421+
level: 'inline',
422+
start(src) {
423+
return src.match(/\[\[/)?.index
424+
},
425+
tokenizer(src) {
426+
const rule = /^\[\[([^\[\]]+)\]\]/
427+
const match = rule.exec(src)
428+
if (match) {
429+
return {
430+
type: 'wikiLink',
431+
raw: match[0],
432+
text: match[1].trim(),
433+
tokens: []
434+
}
435+
}
436+
return undefined
437+
},
438+
renderer(token) {
439+
const pageName = token.text
440+
const safePageName = pageName
441+
.replace(/[^a-zA-Z0-9-_]/g, '-')
442+
.toLowerCase()
443+
return `<a href="#" class="wiki-link" data-page="${pageName}" data-link-type="page">[[${pageName}]]</a>`
444+
}
445+
}
446+
447+
// Add the extension to marked
448+
marked.use({ extensions: [wikiLinkExtension] })
449+
396450
// Initialize the navbar
397451
const navbarContainer = document.getElementById('navbar')
398452
if (navbarContainer) {
@@ -563,6 +617,7 @@
563617
const [storageType, setStorageType] = useState('')
564618
const [viewMode, setViewMode] = useState(VIEW_MODES.SPLIT)
565619
const editorRef = useRef(null)
620+
const previewContainerRef = useRef(null)
566621
const saveTimeoutRef = useRef(null)
567622

568623
// Load journal entry for the current date
@@ -594,6 +649,66 @@
594649
}
595650
}, [])
596651

652+
// Set up event listener for wiki links
653+
useEffect(() => {
654+
if (previewContainerRef.current) {
655+
const handleWikiLinkClick = e => {
656+
// Check if the clicked element is a wiki link
657+
if (e.target.classList.contains('wiki-link')) {
658+
e.preventDefault()
659+
const pageName = e.target.dataset.page
660+
const linkType = e.target.dataset.linkType
661+
662+
if (pageName) {
663+
if (linkType === 'page') {
664+
// Navigate to pages.html with the page name
665+
window.location.href = `pages.html?page=${encodeURIComponent(
666+
pageName
667+
)}`
668+
} else {
669+
// Try to extract a date from the link, or use today's date
670+
let date
671+
const dateParts = pageName.split('_')
672+
if (dateParts.length === 3) {
673+
try {
674+
date = new Date(
675+
parseInt(dateParts[0]),
676+
parseInt(dateParts[1]) - 1,
677+
parseInt(dateParts[2])
678+
)
679+
if (isNaN(date.getTime())) {
680+
date = new Date()
681+
}
682+
} catch (e) {
683+
date = new Date()
684+
}
685+
} else {
686+
date = new Date()
687+
}
688+
setCurrentDate(date)
689+
}
690+
}
691+
}
692+
}
693+
694+
// Add click event listener to the preview container
695+
previewContainerRef.current.addEventListener(
696+
'click',
697+
handleWikiLinkClick
698+
)
699+
700+
// Clean up the event listener
701+
return () => {
702+
if (previewContainerRef.current) {
703+
previewContainerRef.current.removeEventListener(
704+
'click',
705+
handleWikiLinkClick
706+
)
707+
}
708+
}
709+
}
710+
}, [content, viewMode])
711+
597712
// Load all journal entries
598713
const loadJournalEntries = async () => {
599714
const entries = await JournalStorage.getJournalIndex()
@@ -684,6 +799,42 @@
684799
}
685800
}
686801

802+
// Helper function to insert wiki link at cursor
803+
const insertWikiLink = () => {
804+
if (!editorRef.current) return
805+
806+
const textarea = editorRef.current
807+
const start = textarea.selectionStart
808+
const end = textarea.selectionEnd
809+
const selectedText = textarea.value.substring(start, end)
810+
811+
// Prepare the wiki link text - use selection or prompt for page name
812+
let linkText
813+
if (selectedText) {
814+
linkText = selectedText
815+
} else {
816+
linkText = prompt('Enter page name:', 'page-name')
817+
if (!linkText) return // User canceled the prompt
818+
}
819+
820+
const wikiLink = `[[${linkText}]]`
821+
822+
// Insert the wiki link at the cursor position
823+
const newContent =
824+
textarea.value.substring(0, start) +
825+
wikiLink +
826+
textarea.value.substring(end)
827+
828+
setContent(newContent)
829+
830+
// Focus and set cursor position after the inserted text
831+
setTimeout(() => {
832+
textarea.focus()
833+
const newPosition = start + wikiLink.length
834+
textarea.setSelectionRange(newPosition, newPosition)
835+
}, 0)
836+
}
837+
687838
// Main class for the editor/preview container based on view mode
688839
const getMainClass = () => {
689840
switch (viewMode) {
@@ -830,6 +981,31 @@
830981
</svg>
831982
</div>
832983
`}
984+
985+
<!-- Add Wiki Link button -->
986+
<div
987+
class="view-option"
988+
onClick=${insertWikiLink}
989+
title="Insert Wiki Link"
990+
>
991+
<svg
992+
width="16"
993+
height="16"
994+
viewBox="0 0 24 24"
995+
fill="none"
996+
stroke="currentColor"
997+
stroke-width="2"
998+
stroke-linecap="round"
999+
stroke-linejoin="round"
1000+
>
1001+
<path
1002+
d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"
1003+
></path>
1004+
<path
1005+
d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"
1006+
></path>
1007+
</svg>
1008+
</div>
8331009
</div>
8341010
</div>
8351011
<div class="date-nav">
@@ -904,7 +1080,7 @@
9041080
`}
9051081
</div>
9061082
907-
<div class="preview-container">
1083+
<div class="preview-container" ref=${previewContainerRef}>
9081084
<div
9091085
class="preview"
9101086
dangerouslySetInnerHTML=${{ __html: marked.parse(content) }}

pages.html

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -632,6 +632,15 @@
632632
loadContent()
633633
}, [currentPage])
634634

635+
// Check for page parameter in URL on initial load
636+
useEffect(() => {
637+
const queryParams = new URLSearchParams(window.location.search)
638+
const pageParam = queryParams.get('page')
639+
if (pageParam) {
640+
setCurrentPage(pageParam)
641+
}
642+
}, [])
643+
635644
// Load saved view mode from localStorage
636645
useEffect(() => {
637646
const savedViewMode = localStorage.getItem('page_view_mode')

0 commit comments

Comments
 (0)