ui updates
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div :class="['note-row', { 'move-active': moveActive }]">
|
<div :class="['note-row', { 'move-active': moveActive }]">
|
||||||
<span class="date">{{ formatDate(note.createdAt) }}</span>
|
<span class="date">{{ formatDate(note.updatedAt) }}</span>
|
||||||
<div class="title-actions">
|
<div class="title-actions">
|
||||||
<button class="title bold" @click="openNote(note.id)">
|
<button class="title bold" @click="openNote(note.id)">
|
||||||
{{ note.title }}
|
{{ note.title }}
|
||||||
@@ -18,7 +18,6 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import useOpenNote from '@/composables/useOpenNote'
|
import useOpenNote from '@/composables/useOpenNote'
|
||||||
import useState from '@/composables/useState'
|
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
import { format } from 'fecha'
|
import { format } from 'fecha'
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="showScrollBar" class="scroll-bar">
|
<div v-if="showScrollBar" :class="['scroll-bar', { active: isDragging }]">
|
||||||
<div class="inner" ref="inner">
|
<div class="inner" ref="inner">
|
||||||
<div class="handle" ref="handle" />
|
<div class="handle" ref="handle" />
|
||||||
</div>
|
</div>
|
||||||
@@ -7,10 +7,14 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onBeforeUnmount, computed, watch } from 'vue'
|
import {
|
||||||
import { useElementSize, useWindowScroll, useWindowSize } from '@vueuse/core'
|
useElementSize,
|
||||||
import Tempus from 'tempus'
|
useWindowScroll,
|
||||||
|
useWindowSize,
|
||||||
|
useEventListener,
|
||||||
|
} from '@vueuse/core'
|
||||||
import { useDragControls } from '@/composables/useDragControls'
|
import { useDragControls } from '@/composables/useDragControls'
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
|
||||||
const inner = ref()
|
const inner = ref()
|
||||||
const handle = ref()
|
const handle = ref()
|
||||||
@@ -23,12 +27,13 @@ const { height: innerHeight } = useElementSize(inner)
|
|||||||
const { height: handleHeight } = useElementSize(handle)
|
const { height: handleHeight } = useElementSize(handle)
|
||||||
|
|
||||||
// Drag controls
|
// Drag controls
|
||||||
// useDragControls({
|
const { isDragging } = useDragControls({
|
||||||
// target: handle,
|
target: inner,
|
||||||
// onUpdate: ({ y }) => {
|
onUpdate: ({ y }) => {
|
||||||
// console.log(y.value)
|
if (!handle.value) return
|
||||||
// },
|
window.scrollTo(0, y.value * (documentHeight.value - wHeight.value))
|
||||||
// })
|
},
|
||||||
|
})
|
||||||
|
|
||||||
const updateScrollbar = () => {
|
const updateScrollbar = () => {
|
||||||
const scrollHeight = documentHeight.value
|
const scrollHeight = documentHeight.value
|
||||||
@@ -46,27 +51,11 @@ const updateScrollbar = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
useEventListener(window, 'scroll', updateScrollbar)
|
||||||
|
|
||||||
const showScrollBar = computed(() => {
|
const showScrollBar = computed(() => {
|
||||||
return documentHeight.value > wHeight.value
|
return documentHeight.value > wHeight.value
|
||||||
})
|
})
|
||||||
|
|
||||||
// RAF
|
|
||||||
const removeRaf = ref()
|
|
||||||
const addRaf = () => (removeRaf.value = Tempus.add(updateScrollbar))
|
|
||||||
onBeforeUnmount(() => {
|
|
||||||
removeRaf.value?.()
|
|
||||||
})
|
|
||||||
watch(
|
|
||||||
showScrollBar,
|
|
||||||
(show) => {
|
|
||||||
if (show) {
|
|
||||||
addRaf()
|
|
||||||
} else {
|
|
||||||
removeRaf.value?.()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ immediate: true },
|
|
||||||
)
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@@ -79,6 +68,7 @@ watch(
|
|||||||
will-change: transform;
|
will-change: transform;
|
||||||
border-left: 1px solid var(--grey-100);
|
border-left: 1px solid var(--grey-100);
|
||||||
background: var(--theme-bg);
|
background: var(--theme-bg);
|
||||||
|
cursor: grab;
|
||||||
|
|
||||||
.inner {
|
.inner {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@@ -86,7 +76,7 @@ watch(
|
|||||||
|
|
||||||
.handle {
|
.handle {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 388px;
|
height: 70vh;
|
||||||
background: var(--grey-100);
|
background: var(--grey-100);
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -94,5 +84,8 @@ watch(
|
|||||||
will-change: transform;
|
will-change: transform;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
&.active {
|
||||||
|
cursor: grabbing;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="note-download">
|
<div class="note-download">
|
||||||
<button @click="download">
|
<button v-if="noteTitle && props.editor" @click="download">
|
||||||
<span class="title-text">{{ noteTitle }}</span>
|
<span class="title-text">{{ noteTitle }}</span>
|
||||||
<span class="extension">.md ↓</span>
|
<span class="extension">.md ↓</span>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ import EditorMenu from './Menu.vue'
|
|||||||
const TITLE_CHAR_LIMIT = 100
|
const TITLE_CHAR_LIMIT = 100
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
id: {
|
note: {
|
||||||
type: String,
|
type: Object,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -53,23 +53,20 @@ const onUpdate = _debounce(async ({ editor }) => {
|
|||||||
const json = editor.getJSON()
|
const json = editor.getJSON()
|
||||||
const text = editor.getText()
|
const text = editor.getText()
|
||||||
|
|
||||||
await updateNote(props.id, {
|
await updateNote(props.note.id, {
|
||||||
content: json,
|
content: json,
|
||||||
plainText: text,
|
plainText: text,
|
||||||
})
|
})
|
||||||
}, 500)
|
}, 500)
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
const note = await loadNote(props.id)
|
if (props.note.title !== 'Untitled') {
|
||||||
if (!note) return
|
title.value = props.note.title || ''
|
||||||
|
|
||||||
if (note.title !== 'Untitled') {
|
|
||||||
title.value = note.title || ''
|
|
||||||
}
|
}
|
||||||
|
|
||||||
editor.value = new Editor({
|
editor.value = new Editor({
|
||||||
extensions,
|
extensions,
|
||||||
content: note.content || [],
|
content: props.note.content || [],
|
||||||
onUpdate: onUpdate,
|
onUpdate: onUpdate,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -95,7 +92,7 @@ watch(title, async (newVal) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
const updateTitle = _debounce((title) => {
|
const updateTitle = _debounce((title) => {
|
||||||
updateNote(props.id, {
|
updateNote(props.note.id, {
|
||||||
title: title === '' ? 'Untitled' : title,
|
title: title === '' ? 'Untitled' : title,
|
||||||
})
|
})
|
||||||
}, 500)
|
}, 500)
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ export function useDragControls(options = {}) {
|
|||||||
const isDragging = ref(false)
|
const isDragging = ref(false)
|
||||||
|
|
||||||
let bounds = null
|
let bounds = null
|
||||||
|
let cleanupSelectListener = null
|
||||||
|
|
||||||
|
const disableSelect = (e) => e.preventDefault()
|
||||||
|
|
||||||
const updateBounds = () => {
|
const updateBounds = () => {
|
||||||
if (target) {
|
if (target) {
|
||||||
@@ -35,6 +38,9 @@ export function useDragControls(options = {}) {
|
|||||||
isDragging.value = true
|
isDragging.value = true
|
||||||
updateBounds()
|
updateBounds()
|
||||||
move(e)
|
move(e)
|
||||||
|
|
||||||
|
// Disable text selection
|
||||||
|
cleanupSelectListener = useEventListener('selectstart', disableSelect)
|
||||||
}
|
}
|
||||||
|
|
||||||
const move = (e) => {
|
const move = (e) => {
|
||||||
@@ -49,6 +55,8 @@ export function useDragControls(options = {}) {
|
|||||||
|
|
||||||
const end = () => {
|
const end = () => {
|
||||||
isDragging.value = false
|
isDragging.value = false
|
||||||
|
|
||||||
|
cleanupSelectListener?.()
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<main class="note layout-block">
|
<main class="note layout-block">
|
||||||
<note-download :title="editorRef?.title" :editor="editorRef?.editor" />
|
<note-download :title="note.title" :editor="editorRef?.editor" />
|
||||||
|
|
||||||
<note-find
|
<note-find
|
||||||
:editor="editorRef?.editor"
|
:editor="editorRef?.editor"
|
||||||
:visible="findVisible"
|
:visible="findVisible"
|
||||||
@close="findVisible = false"
|
@close="findVisible = false"
|
||||||
/>
|
/>
|
||||||
<note-editor ref="editorRef" :id="id" />
|
<note-editor :note="note" ref="editorRef" />
|
||||||
</main>
|
</main>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
import { ref, watchEffect } from 'vue'
|
import { ref, watchEffect } from 'vue'
|
||||||
import { useMagicKeys } from '@vueuse/core'
|
import { useMagicKeys } from '@vueuse/core'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
|
import useNotes from '@/composables/useNotes'
|
||||||
import NoteEditor from '@/components/note/Editor.vue'
|
import NoteEditor from '@/components/note/Editor.vue'
|
||||||
import NoteFind from '@/components/note/Find.vue'
|
import NoteFind from '@/components/note/Find.vue'
|
||||||
import NoteDownload from '@/components/note/Download.vue'
|
import NoteDownload from '@/components/note/Download.vue'
|
||||||
@@ -22,9 +23,13 @@ import NoteDownload from '@/components/note/Download.vue'
|
|||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const id = route.params.id
|
const id = route.params.id
|
||||||
|
|
||||||
|
const { loadNote } = useNotes()
|
||||||
|
const note = await loadNote(id)
|
||||||
|
|
||||||
const editorRef = ref(null)
|
const editorRef = ref(null)
|
||||||
const findVisible = ref(false)
|
const findVisible = ref(false)
|
||||||
|
|
||||||
|
// Find shortcut
|
||||||
const { ctrl, f } = useMagicKeys()
|
const { ctrl, f } = useMagicKeys()
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
if (ctrl.value && f.value) {
|
if (ctrl.value && f.value) {
|
||||||
|
|||||||
Reference in New Issue
Block a user