feat: add initial markdown support via extra markdown component

This commit is contained in:
nisch.codes 2025-03-16 14:07:15 +01:00
parent 2275c5dbd1
commit 6273029e77
8 changed files with 2069 additions and 1833 deletions

3728
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -3,25 +3,28 @@
"private": true,
"version": "1.0.1",
"type": "module",
"description": "Just another note editor written in VUE.js for learning purposes.",
"homepage": "https://projects.nisch.codes/nischcodes/JANE#readme",
"author": "nisch.codes <nischcodes@noreply.projects.nisch.codes>",
"license": "GPL-3.0",
"keywords": [],
"repository": {
"type": "git",
"url": "https://projects.nisch.codes/nischcodes/JANE.git"
},
"description": "Just another note editor written in VUE.js for learning purposes.",
"homepage": "https://projects.nisch.codes/nischcodes/JANE#readme",
"author": "nisch.codes <nischcodes@noreply.projects.nisch.codes>",
"license": "GPL-3.0",
"keywords": [],
"repository": {
"type": "git",
"url": "https://projects.nisch.codes/nischcodes/JANE.git"
},
"bugs": {
"url": "https://projects.nisch.codes/nischcodes/JANE/issues"
},
"url": "https://projects.nisch.codes/nischcodes/JANE/issues"
},
"scripts": {
"dev": "vite",
"build": "vue-tsc -b && vite build",
"preview": "vite preview"
},
"dependencies": {
"@tailwindcss/typography": "^0.5.16",
"@tailwindcss/vite": "^4.0.14",
"dompurify": "^3.2.4",
"marked": "^15.0.7",
"tailwindcss": "^4.0.14",
"vue": "^3.5.13"
},

Binary file not shown.

After

(image error) Size: 7.7 MiB

@ -1,6 +1,7 @@
<script setup lang="ts">
import {ref, watchEffect} from 'vue'
import {ref, watchEffect, nextTick} from 'vue'
import Sidebar from './components/Sidebar.vue'
import MarkdownEditor from './components/MarkdownEditor.vue'
const STORAGE_KEY_CONFIG = 'jane-config'
const STORAGE_KEY_NOTES = 'jane-notes'
@ -54,6 +55,16 @@ function update_note() {
notes.value[noteId].content = input_content.value
}
// update note content
function update_note_content({id, content}:any) {
// find the current note id in the notes array
let noteId = findNoteIndexById(id)
// set the note properties to the current input values
notes.value[noteId].content = content
// update the ref object
input_content.value = content
}
// set active note
function set_active_note(id:any) {
// set the active note property
@ -63,8 +74,8 @@ function set_active_note(id:any) {
// set the input properties to the current note
input_title.value = notes.value[noteId].title
input_content.value = notes.value[noteId].content
// set timeout to wait a tick to get it ready
setTimeout(() => { (document.querySelector('input#note-title') as HTMLInputElement)?.focus() }, 0)
// wait a tick and focus the input field
nextTick(() => { (document.querySelector('input#note-title') as HTMLInputElement)?.focus() })
}
// persist state
@ -99,13 +110,22 @@ watchEffect(() => {
id="note-title"
class="block w-full text-3xl pb-2 font-bold border-b-2 border-gray-500 focus:border-white outline-none transition-colors duration-200"
/>
<textarea
<!--textarea
v-model="input_content"
@input="update_note"
name="note-content"
id="note-content"
class="block w-full h-full mt-4 text-lg outline-none flex-1"
></textarea>
class="block w-full h-full mt-4 text-lg flex-1"
></textarea-->
<MarkdownEditor
:active_note="active_note"
v-model="input_content"
@update-note-content="update_note_content"
name="note-content"
id="note-content"
class="block w-full h-full mt-4 text-lg flex-1"
/>
</div>
</main>
</div>

@ -0,0 +1,61 @@
This is a long note for my test of the local persitents. This is the extended version.
# maybe with some headlines?
* list item 1
* list item 2
* list item 3
* list item 4
This is also very interesting. This for example is **bold** , and this**is**also bold and __this__ also.
But this *is italic* and this is also _italic_ and if I want to make something ***bold and italic*** than this is.
I am a bit hesitant that the next will work
> because this is a quote
but it works. Even the quote in a quote??
> so this is a quote
>> also is this...
After the unsorted lists, there are some sorted lists as well:
1. list item 1
2. list item 2
3. list item 3
maybe we can mix them?
1. list item 1
- list item 1.1
1. list item
---
What about code?
`` console.log('hello world') ``
for code I want to extend the renderer.
---
lets test links:
* [Duck Duck Go](https://duckduckgo.com)
* <https://nisch.codes>
* <info@nisch.codes>
Links should also be extended
---
Next lets try reference links:
* [Project Repository of nisch][1]
* [License of JANE][2]
[1]: https://projects.nisch.codes "gitea Server"
[2]: https://projects.nisch.codes/nischcodes/JANE/src/branch/main/LICENSE
---
Images:
[![An old rock in the desert](images/testimage-4k.jpg "Shiprock, New Mexico by Beau Rogers")](https://www.flickr.com/photos/beaurogers/31833779864/in/photolist-Qv3rFw-34mt9F-a9Cmfy-5Ha3Zi-9msKdv-o3hgjr-hWpUte-4WMsJ1-KUQ8N-deshUb-vssBD-6CQci6-8AFCiD-zsJWT-nNfsgB-dPDwZJ-bn9JGn-5HtSXY-6CUhAL-a4UTXB-ugPum-KUPSo-fBLNm-6CUmpy-4WMsc9-8a7D3T-83KJev-6CQ2bK-nNusHJ-a78rQH-nw3NvT-7aq2qf-8wwBso-3nNceh-ugSKP-4mh4kh-bbeeqH-a7biME-q3PtTf-brFpgb-cg38zw-bXMZc-nJPELD-f58Lmo-bXMYG-bz8AAi-bxNtNT-bXMYi-bXMY6-bXMYv)

@ -0,0 +1,55 @@
<script setup lang="ts">
import { ref, computed, nextTick } from 'vue'
import { marked } from 'marked'
import DOMPurify from 'dompurify'
//const model = defineModel({ default: '' })
const props = defineProps(['active_note'])
const emit = defineEmits(['update-note-content'])
const markdownInput = defineModel({ default: '' })
const isEditing = ref(false)
// render the markdown and sanitize the result
const renderedMarkdown = computed(() => {
// parse raw text into markdown
const rawHTML = marked.parse(markdownInput.value)
// sanitize the raw html from marked
return DOMPurify.sanitize(rawHTML as string)
})
// function to start the edit state
function startEditing() {
// set the edit state to true
isEditing.value = true
// wait a tick and focus the input field
nextTick(() => { (document.querySelector('textarea#editor') as HTMLTextAreaElement)?.focus() })
}
// function to stop the edit state
function stopEditing() {
// set the edit state to false
isEditing.value = false
// update the prop outside this component
emit('update-note-content', {id: props.active_note, content: markdownInput.value})
}
</script>
<template>
<div>
<div
v-if="!isEditing"
class="prose max-w-none w-full h-full text-lg cursor-pointer text-white prose-headings:text-white"
v-html="renderedMarkdown"
@click="startEditing"
></div>
<textarea
v-else
id="editor"
v-model="markdownInput"
@blur="stopEditing"
@keydown.esc.prevent="stopEditing"
class="w-full h-full text-lg outline-none"
></textarea>
</div>
</template>

@ -1,4 +1,5 @@
@import "tailwindcss";
@plugin "@tailwindcss/typography";
@layer components {
.button {