Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions src/application/services/useNote.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ interface UseNoteComposableState {
*/
unlinkParent: () => Promise<void>;

/**
* Returns an array of Note objects representing the formatted note parents.
*/
formatNoteParents: () => Note[];
Comment thread
neSpecc marked this conversation as resolved.
Outdated

/**
* Defines if user can edit note
*/
Expand Down Expand Up @@ -158,6 +163,13 @@ export default function (options: UseNoteComposableOptions): UseNoteComposableSt
*/
const parentNote = ref<Note | undefined>(undefined);

/**
* Note parents of the actual note
*
* Actual note by default
*/
let noteParents: Note[] = [];

/**
* Load note by id
* @param id - Note identifier got from composable argument
Expand All @@ -172,6 +184,7 @@ export default function (options: UseNoteComposableOptions): UseNoteComposableSt
canEdit.value = response.accessRights.canEdit;
noteTools.value = response.tools;
parentNote.value = response.parentNote;
noteParents = response.parents;
}

/**
Expand Down Expand Up @@ -265,6 +278,35 @@ export default function (options: UseNoteComposableOptions): UseNoteComposableSt
parentNote.value = undefined;
}

/**
* Reform the received note parents from api into presentation format.
* @returns An array of Note objects representing the formatted note parents.
* @throws {Error} If the note id is not defined.
*/
Comment thread
neSpecc marked this conversation as resolved.
Outdated
function formatNoteParents(): Note[] {
Comment thread
e11sy marked this conversation as resolved.
Outdated
if (currentId.value === null) {
return [];
}
let presentationFormat: Note[] = [];

if (noteParents.length === 0) {
presentationFormat.push({
id: currentId.value,
content: note.value?.content as NoteContent,
});
Comment thread
neSpecc marked this conversation as resolved.
Outdated
} else {
presentationFormat = noteParents;
if (noteParents.find(noteItem => noteItem.id === currentId.value) === undefined) {
presentationFormat.push({
id: currentId.value,
content: note.value?.content as NoteContent,
});
}
}

return presentationFormat;
}

/**
* Get note by custom hostname
*/
Expand Down Expand Up @@ -315,6 +357,7 @@ export default function (options: UseNoteComposableOptions): UseNoteComposableSt
});

watch(noteTitle, (currentNoteTitle) => {
formatNoteParents();
patchOpenedPageByUrl(
route.path,
{
Expand All @@ -332,6 +375,7 @@ export default function (options: UseNoteComposableOptions): UseNoteComposableSt
resolveToolsByContent,
save,
unlinkParent,
formatNoteParents,
parentNote,
};
}
5 changes: 5 additions & 0 deletions src/domain/entities/NoteDTO.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,9 @@ export interface NoteDTO {
* Editor tools
*/
tools: EditorTool[];

/**
* Note parents
*/
parents: Note[];
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ export type GetNoteResponsePayload = {
accessRights: NoteAccessRights;
parentNote: Note | undefined;
tools: EditorTool[];
parents: Note[];
};
83 changes: 74 additions & 9 deletions src/presentation/pages/Note.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,18 @@
:style="{ '--opacity': id && note ? 1 : 0 }"
>
<template #left>
{{
note && 'updatedAt' in note && note.updatedAt
? t('note.lastEdit') + ' ' + getTimeFromNow(note.updatedAt)
: t('note.lastEdit') + ' ' + 'a few seconds ago'
}}
Comment thread
neSpecc marked this conversation as resolved.
<div v-if="noteParents.length">
<span
Comment thread
neSpecc marked this conversation as resolved.
Outdated
v-for="(parent, index) in displayedParents"
:key="parent.id"
>
<a @click="handleParentClick(parent)">{{ newGetTitle(parent.content) }}</a>
Comment thread
neSpecc marked this conversation as resolved.
Outdated
<span v-if="index < displayedParents.length - 1"> > </span>
</span>
</div>
<div v-else>
{{ t('note.lastEdit') + ' ' + 'a few seconds ago' }}
</div>
</template>
<template #right>
<Button
Expand Down Expand Up @@ -48,18 +55,18 @@
</template>

<script lang="ts" setup>
import { ref, toRef, watch } from 'vue';
import { computed, ref, toRef, watch } from 'vue';
import { Button, Editor } from 'codex-ui/vue';
import useNote from '@/application/services/useNote';
import { useRouter } from 'vue-router';
import { NoteContent } from '@/domain/entities/Note';
import { Note, NoteContent } from '@/domain/entities/Note';
import { useHead } from 'unhead';
import { useI18n } from 'vue-i18n';
import { getTimeFromNow } from '@/infrastructure/utils/date';
import { makeElementScreenshot } from '@/infrastructure/utils/screenshot';
import useNoteSettings from '@/application/services/useNoteSettings';
import { useNoteEditor } from '@/application/services/useNoteEditor';
import NoteHeader from '@/presentation/components/note-header/NoteHeader.vue';
import { OutputData } from '@editorjs/editorjs';

const { t } = useI18n();

Expand All @@ -79,10 +86,12 @@ const props = defineProps<{

const noteId = toRef(props, 'id');

const { note, noteTools, save, noteTitle, canEdit } = useNote({
const { note, noteTools, save, noteTitle, canEdit, formatNoteParents } = useNote({
id: noteId,
});

let noteParents: Note[] = [];

/**
* Create new child note
*/
Expand All @@ -103,6 +112,61 @@ function redirectToNoteSettings(): void {
router.push(`/note/${props.id}/settings`);
}

/**
* Navigate to a specific note
*
* @param {number} parentId - The ID of the parent note to navigate to
*/
function navigateToParent(parentId: string): void {
Comment thread
neSpecc marked this conversation as resolved.
Outdated
router.push(`/note/${parentId}`);
}

/**
* Handle parent click
*
* @param {object} parent - The parent object
* @param {string} parent.id - The ID of the parent note
*/
function handleParentClick(parent: { id: string }): void {
if (parent.id !== 'ellipsis') {
Comment thread
neSpecc marked this conversation as resolved.
Outdated
navigateToParent(parent.id);
}
}

/**
* Displayed parents
Comment thread
neSpecc marked this conversation as resolved.
Outdated
*/
const displayedParents = computed(() => {
if (noteParents.length > 3) {
return [
noteParents[0],
{
id: 'ellipsis',
content: {
title: '...',
},
},
noteParents[noteParents.length - 1],
];
}

return noteParents;
});

/**
* Update note cover
*
* @param {OutputData | { title: string }} content - The content of the note
* @returns {string} - The title of the note
*/
function newGetTitle(content: OutputData | { title: string }): string {
Comment thread
neSpecc marked this conversation as resolved.
Outdated
if ('blocks' in content) {
return content.blocks[0]?.data.text || 'Untitled';
}

return content.title;
}

const { updateCover } = useNoteSettings();

const { isEditorReady, editorConfig } = useNoteEditor({
Expand Down Expand Up @@ -169,6 +233,7 @@ watch(
);

watch(noteTitle, () => {
noteParents = formatNoteParents();
if (props.id !== null) {
useHead({
title: noteTitle.value,
Expand Down