Compare commits
4 Commits
2275c5dbd1
...
188e0e9659
Author | SHA1 | Date | |
---|---|---|---|
188e0e9659 | |||
10314cb09d | |||
c5aea90ed3 | |||
6273029e77 |
100
package-lock.json
generated
100
package-lock.json
generated
@ -1,14 +1,18 @@
|
|||||||
{
|
{
|
||||||
"name": "jane",
|
"name": "jane",
|
||||||
"version": "0.0.0",
|
"version": "1.0.1",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "jane",
|
"name": "jane",
|
||||||
"version": "0.0.0",
|
"version": "1.0.1",
|
||||||
|
"license": "GPL-3.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@tailwindcss/typography": "^0.5.16",
|
||||||
"@tailwindcss/vite": "^4.0.14",
|
"@tailwindcss/vite": "^4.0.14",
|
||||||
|
"dompurify": "^3.2.4",
|
||||||
|
"marked": "^15.0.7",
|
||||||
"tailwindcss": "^4.0.14",
|
"tailwindcss": "^4.0.14",
|
||||||
"vue": "^3.5.13"
|
"vue": "^3.5.13"
|
||||||
},
|
},
|
||||||
@ -928,6 +932,21 @@
|
|||||||
"node": ">= 10"
|
"node": ">= 10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@tailwindcss/typography": {
|
||||||
|
"version": "0.5.16",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.16.tgz",
|
||||||
|
"integrity": "sha512-0wDLwCVF5V3x3b1SGXPCDcdsbDHMBe+lkFzBRaHeLvNi+nrrnZ1lA18u+OTWO8iSWU2GxUOCvlXtDuqftc1oiA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"lodash.castarray": "^4.4.0",
|
||||||
|
"lodash.isplainobject": "^4.0.6",
|
||||||
|
"lodash.merge": "^4.6.2",
|
||||||
|
"postcss-selector-parser": "6.0.10"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@tailwindcss/vite": {
|
"node_modules/@tailwindcss/vite": {
|
||||||
"version": "4.0.14",
|
"version": "4.0.14",
|
||||||
"resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.0.14.tgz",
|
"resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.0.14.tgz",
|
||||||
@ -949,6 +968,13 @@
|
|||||||
"integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
|
"integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/trusted-types": {
|
||||||
|
"version": "2.0.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
|
||||||
|
"integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
"node_modules/@vitejs/plugin-vue": {
|
"node_modules/@vitejs/plugin-vue": {
|
||||||
"version": "5.2.1",
|
"version": "5.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.1.tgz",
|
||||||
@ -1171,6 +1197,18 @@
|
|||||||
"balanced-match": "^1.0.0"
|
"balanced-match": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/cssesc": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"cssesc": "bin/cssesc"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/csstype": {
|
"node_modules/csstype": {
|
||||||
"version": "3.1.3",
|
"version": "3.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
||||||
@ -1193,6 +1231,15 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/dompurify": {
|
||||||
|
"version": "3.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.4.tgz",
|
||||||
|
"integrity": "sha512-ysFSFEDVduQpyhzAob/kkuJjf5zWkZD8/A9ywSp1byueyuCfHamrCBa14/Oc2iiB0e51B+NpxSl5gmzn+Ms/mg==",
|
||||||
|
"license": "(MPL-2.0 OR Apache-2.0)",
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@types/trusted-types": "^2.0.7"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/enhanced-resolve": {
|
"node_modules/enhanced-resolve": {
|
||||||
"version": "5.18.1",
|
"version": "5.18.1",
|
||||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz",
|
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz",
|
||||||
@ -1531,6 +1578,24 @@
|
|||||||
"url": "https://opencollective.com/parcel"
|
"url": "https://opencollective.com/parcel"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/lodash.castarray": {
|
||||||
|
"version": "4.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz",
|
||||||
|
"integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/lodash.isplainobject": {
|
||||||
|
"version": "4.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
|
||||||
|
"integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/lodash.merge": {
|
||||||
|
"version": "4.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
||||||
|
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/magic-string": {
|
"node_modules/magic-string": {
|
||||||
"version": "0.30.17",
|
"version": "0.30.17",
|
||||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz",
|
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz",
|
||||||
@ -1540,6 +1605,18 @@
|
|||||||
"@jridgewell/sourcemap-codec": "^1.5.0"
|
"@jridgewell/sourcemap-codec": "^1.5.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/marked": {
|
||||||
|
"version": "15.0.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/marked/-/marked-15.0.7.tgz",
|
||||||
|
"integrity": "sha512-dgLIeKGLx5FwziAnsk4ONoGwHwGPJzselimvlVskE9XLN4Orv9u2VA3GWw/lYUqjfA0rUT/6fqKwfZJapP9BEg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"marked": "bin/marked.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 18"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/minimatch": {
|
"node_modules/minimatch": {
|
||||||
"version": "9.0.5",
|
"version": "9.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
|
||||||
@ -1622,6 +1699,19 @@
|
|||||||
"node": "^10 || ^12 || >=14"
|
"node": "^10 || ^12 || >=14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/postcss-selector-parser": {
|
||||||
|
"version": "6.0.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz",
|
||||||
|
"integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"cssesc": "^3.0.0",
|
||||||
|
"util-deprecate": "^1.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/rollup": {
|
"node_modules/rollup": {
|
||||||
"version": "4.35.0",
|
"version": "4.35.0",
|
||||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.35.0.tgz",
|
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.35.0.tgz",
|
||||||
@ -1698,6 +1788,12 @@
|
|||||||
"node": ">=14.17"
|
"node": ">=14.17"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/util-deprecate": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/vite": {
|
"node_modules/vite": {
|
||||||
"version": "6.2.2",
|
"version": "6.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-6.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-6.2.2.tgz",
|
||||||
|
@ -21,7 +21,10 @@
|
|||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@tailwindcss/typography": "^0.5.16",
|
||||||
"@tailwindcss/vite": "^4.0.14",
|
"@tailwindcss/vite": "^4.0.14",
|
||||||
|
"dompurify": "^3.2.4",
|
||||||
|
"marked": "^15.0.7",
|
||||||
"tailwindcss": "^4.0.14",
|
"tailwindcss": "^4.0.14",
|
||||||
"vue": "^3.5.13"
|
"vue": "^3.5.13"
|
||||||
},
|
},
|
||||||
|
72
public/data/markdown-test.md
Normal file
72
public/data/markdown-test.md
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
This is the testing Note for all the Markdown features.
|
||||||
|
|
||||||
|
# Heading 1
|
||||||
|
## Heading 2
|
||||||
|
### Heading 3
|
||||||
|
#### Heading 4
|
||||||
|
##### Heading 5
|
||||||
|
###### Heading 6
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
This is some text which includes **bold** text and some more __bold__ text. But also some *italic* text and more _italic_ text. There is even text with a mixture of ***bold and italic*** text.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Must texts have some quotes included, so this note also have some quotes...
|
||||||
|
|
||||||
|
> This is a single quote
|
||||||
|
|
||||||
|
...and quotes in quotes.
|
||||||
|
> This is the outer quote
|
||||||
|
>> This is a inner quote
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
When it comes to lists, there are quite a few.
|
||||||
|
|
||||||
|
First there is the unsorted list:
|
||||||
|
|
||||||
|
* list item 1
|
||||||
|
* list item 2
|
||||||
|
* list item 3
|
||||||
|
|
||||||
|
Second there are the sorted lists:
|
||||||
|
|
||||||
|
1. list item 1
|
||||||
|
2. list item 2
|
||||||
|
3. list item 3
|
||||||
|
|
||||||
|
Lastly you can combine both types of lists:
|
||||||
|
|
||||||
|
1. list item 1
|
||||||
|
- list item 1.1
|
||||||
|
1. list item
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Another big topic is links. You can specify the link text, or not and you can use mail-addresses to generate a mailto link.
|
||||||
|
|
||||||
|
* [Nisch's projects and git server](https://projects.nisch.codes)
|
||||||
|
* <https://nisch.codes>
|
||||||
|
* <info@nisch.codes>
|
||||||
|
|
||||||
|
Next reference links:
|
||||||
|
|
||||||
|
* [JANE's Repository][1]
|
||||||
|
* [JANE's License][2]
|
||||||
|
|
||||||
|
[1]: https://projects.nisch.codes/nischcodes/JANE "JANE - git repository"
|
||||||
|
[2]: https://projects.nisch.codes/nischcodes/JANE/src/branch/main/LICENSE
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Images:
|
||||||
|
|
||||||
|
[](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)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
At the end, there is Code:
|
||||||
|
|
||||||
|
`` console.log('hello world') ``
|
BIN
public/images/testimage-4k.jpg
Normal file
BIN
public/images/testimage-4k.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.7 MiB |
63
src/App.vue
63
src/App.vue
@ -1,6 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {ref, watchEffect} from 'vue'
|
import {ref, watchEffect, nextTick, onMounted, onUnmounted} from 'vue'
|
||||||
import Sidebar from './components/Sidebar.vue'
|
import Sidebar from './components/Sidebar.vue'
|
||||||
|
import MarkdownEditor from './components/MarkdownEditor.vue'
|
||||||
|
|
||||||
const STORAGE_KEY_CONFIG = 'jane-config'
|
const STORAGE_KEY_CONFIG = 'jane-config'
|
||||||
const STORAGE_KEY_NOTES = 'jane-notes'
|
const STORAGE_KEY_NOTES = 'jane-notes'
|
||||||
@ -12,20 +13,48 @@ const active_note = ref(null)
|
|||||||
const input_title = ref('')
|
const input_title = ref('')
|
||||||
const input_content = ref('')
|
const input_content = ref('')
|
||||||
|
|
||||||
|
const loadMarkdown = async () => {
|
||||||
|
// load markdown file
|
||||||
|
const response = await fetch('/data/markdown-test.md')
|
||||||
|
// save the content
|
||||||
|
let markdown = await response.text()
|
||||||
|
// create a new note
|
||||||
|
create_note('Markdown Test Note', markdown)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleKeydown = (event:any) => {
|
||||||
|
if (event.ctrlKey && event.shiftKey && event.key.toLowerCase() === 'm') {
|
||||||
|
// prevent the default behaviour
|
||||||
|
event.preventDefault()
|
||||||
|
// some messages for the easter egg
|
||||||
|
console.log('CTRL + SHIFT + M pressed!')
|
||||||
|
// call the load function
|
||||||
|
loadMarkdown()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => { window.addEventListener('keydown', handleKeydown) })
|
||||||
|
onUnmounted(() => { window.removeEventListener('keydown', handleKeydown) })
|
||||||
|
|
||||||
// find note Index by Id
|
// find note Index by Id
|
||||||
function findNoteIndexById(id:any):any {
|
function findNoteIndexById(id:any):any {
|
||||||
return notes.value.findIndex((note:any) => note.id === id)
|
return notes.value.findIndex((note:any) => note.id === id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// create random id
|
||||||
|
function createRandomId():string {
|
||||||
|
return Math.random().toString(36).substring(2,9)
|
||||||
|
}
|
||||||
|
|
||||||
// create note
|
// create note
|
||||||
function create_note() {
|
function create_note(title:string = 'Untitled', content:string = '') {
|
||||||
// generate random id
|
// generate random id
|
||||||
const id = Math.random().toString(36).substring(2,9)
|
const id = createRandomId()
|
||||||
// push new note to notes array
|
// push new note to notes array
|
||||||
notes.value.push({
|
notes.value.push({
|
||||||
id,
|
id,
|
||||||
title: 'Untitled',
|
title: title,
|
||||||
content: ''
|
content: content
|
||||||
})
|
})
|
||||||
// set active note to id
|
// set active note to id
|
||||||
set_active_note(id)
|
set_active_note(id)
|
||||||
@ -54,6 +83,16 @@ function update_note() {
|
|||||||
notes.value[noteId].content = input_content.value
|
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
|
// set active note
|
||||||
function set_active_note(id:any) {
|
function set_active_note(id:any) {
|
||||||
// set the active note property
|
// set the active note property
|
||||||
@ -63,8 +102,8 @@ function set_active_note(id:any) {
|
|||||||
// set the input properties to the current note
|
// set the input properties to the current note
|
||||||
input_title.value = notes.value[noteId].title
|
input_title.value = notes.value[noteId].title
|
||||||
input_content.value = notes.value[noteId].content
|
input_content.value = notes.value[noteId].content
|
||||||
// set timeout to wait a tick to get it ready
|
// wait a tick and focus the input field
|
||||||
setTimeout(() => { (document.querySelector('input#note-title') as HTMLInputElement)?.focus() }, 0)
|
nextTick(() => { (document.querySelector('input#note-title') as HTMLInputElement)?.focus() })
|
||||||
}
|
}
|
||||||
|
|
||||||
// persist state
|
// persist state
|
||||||
@ -99,13 +138,15 @@ watchEffect(() => {
|
|||||||
id="note-title"
|
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"
|
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
|
|
||||||
|
<MarkdownEditor
|
||||||
|
:active_note="active_note"
|
||||||
v-model="input_content"
|
v-model="input_content"
|
||||||
@input="update_note"
|
@update-note-content="update_note_content"
|
||||||
name="note-content"
|
name="note-content"
|
||||||
id="note-content"
|
id="note-content"
|
||||||
class="block w-full h-full mt-4 text-lg outline-none flex-1"
|
class="block w-full h-full mt-4 text-lg flex-1"
|
||||||
></textarea>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
55
src/components/MarkdownEditor.vue
Normal file
55
src/components/MarkdownEditor.vue
Normal file
@ -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 prose-strong:text-white prose-em:text-white prose-blockquote:text-white prose-code:text-white prose-a:text-white marker: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";
|
@import "tailwindcss";
|
||||||
|
@plugin "@tailwindcss/typography";
|
||||||
|
|
||||||
@layer components {
|
@layer components {
|
||||||
.button {
|
.button {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user