Skip to content

Commit 58dbc8c

Browse files
Merge pull request #275 from codex-team/feat/note-parents
feat: display the note parents structure
2 parents db31174 + f4d6f66 commit 58dbc8c

File tree

5 files changed

+92
-12
lines changed

5 files changed

+92
-12
lines changed

src/application/services/useNote.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,11 @@ interface UseNoteComposableState {
7272
*/
7373
unlinkParent: () => Promise<void>;
7474

75+
/**
76+
* Returns an array of note parents for the current note.
77+
*/
78+
noteParents: Ref<Note[]>;
79+
7580
/**
7681
* Defines if user can edit note
7782
*/
@@ -165,6 +170,12 @@ export default function (options: UseNoteComposableOptions): UseNoteComposableSt
165170
*/
166171
const parentNote = ref<Note | undefined>(undefined);
167172

173+
/**
174+
* Note parents of the actual note
175+
*
176+
* Actual note by default
177+
*/
178+
const noteParents = ref<Note[]>([]);
168179
/**
169180
* Note hierarchy
170181
*
@@ -194,6 +205,7 @@ export default function (options: UseNoteComposableOptions): UseNoteComposableSt
194205
canEdit.value = response.accessRights.canEdit;
195206
noteTools.value = response.tools;
196207
parentNote.value = response.parentNote;
208+
noteParents.value = response.parents;
197209
void getNoteHierarchy(id);
198210
} catch (error) {
199211
deleteOpenedPageByUrl(route.path);
@@ -399,6 +411,7 @@ export default function (options: UseNoteComposableOptions): UseNoteComposableSt
399411
resolveToolsByContent,
400412
save,
401413
unlinkParent,
414+
noteParents,
402415
parentNote,
403416
noteHierarchy,
404417
};

src/domain/entities/NoteDTO.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,9 @@ export interface NoteDTO {
2525
* Editor tools
2626
*/
2727
tools: EditorTool[];
28+
29+
/**
30+
* Note parents
31+
*/
32+
parents: Note[];
2833
}

src/infrastructure/transport/notes-api/types/GetNoteResponsePayload.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ export type GetNoteResponsePayload = {
1010
accessRights: NoteAccessRights;
1111
parentNote: Note | undefined;
1212
tools: EditorTool[];
13+
parents: Note[];
1314
};
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<template>
2+
<RouterLink
3+
v-for="(parent, index) in displayedParents"
4+
:key="index"
5+
:to="{ path: parent.id ? `/note/${parent.id}` : '' }"
6+
class="breadcrumb"
7+
>
8+
{{ parent.content ? getTitle(parent.content) : '...' }}
9+
<Icon
10+
v-if="index < displayedParents.length - 1"
11+
name="ChevronRight"
12+
/>
13+
</RouterLink>
14+
</template>
15+
16+
<script setup lang="ts">
17+
18+
import { getTitle } from '@/infrastructure/utils/note.ts';
19+
import { RouterLink } from 'vue-router';
20+
import { computed } from 'vue';
21+
import { Note } from '@/domain/entities/Note.ts';
22+
import { Icon } from '@codexteam/ui/vue';
23+
24+
const props = defineProps<{
25+
noteParents: Note[];
26+
}>();
27+
/**
28+
* Note parents hierarchy
29+
* If there are more than 3, only the closest & the furthest ones are shown
30+
*/
31+
const displayedParents = computed(() => {
32+
if (props.noteParents.length > 3) {
33+
return [
34+
props.noteParents[0],
35+
{ id: '',
36+
content: null },
37+
props.noteParents[props.noteParents.length - 1],
38+
];
39+
}
40+
41+
return props.noteParents;
42+
});
43+
</script>
44+
45+
<style scoped>
46+
.breadcrumb {
47+
display: inline-flex;
48+
align-items: center;
49+
}
50+
</style>

src/presentation/pages/Note.vue

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,18 @@
44
:style="{ '--opacity': id && note ? 1 : 0 }"
55
>
66
<template #left>
7-
{{
8-
note && 'updatedAt' in note && note.updatedAt
9-
? t('note.lastEdit') + ' ' + getTimeFromNow(note.updatedAt)
10-
: t('note.lastEdit') + ' ' + 'a few seconds ago'
11-
}}
7+
<BreadCrumbs
8+
:note-parents="noteParents"
9+
/>
1210
</template>
1311
<template #right>
12+
<div class="last_edit">
13+
{{
14+
note && 'updatedAt' in note && note.updatedAt
15+
? t('note.lastEdit') + ' ' + getTimeFromNow(note.updatedAt)
16+
: t('note.lastEdit') + ' ' + 'a few seconds ago'
17+
}}
18+
</div>
1419
<Button
1520
v-if="canEdit"
1621
secondary
@@ -59,19 +64,20 @@
5964

6065
<script lang="ts" setup>
6166
import { computed, ref, toRef, watch } from 'vue';
62-
import { Button, Editor, type VerticalMenuItem, VerticalMenu, PageBlock } from '@codexteam/ui/vue';
67+
import { Button, Editor, PageBlock, VerticalMenu, type VerticalMenuItem } from '@codexteam/ui/vue';
6368
import useNote from '@/application/services/useNote';
6469
import { useRoute, useRouter } from 'vue-router';
6570
import { NoteContent } from '@/domain/entities/Note';
6671
import { useHead } from 'unhead';
6772
import { useI18n } from 'vue-i18n';
68-
import { getTimeFromNow } from '@/infrastructure/utils/date';
6973
import { makeElementScreenshot } from '@/infrastructure/utils/screenshot';
7074
import useNoteSettings from '@/application/services/useNoteSettings';
7175
import { useNoteEditor } from '@/application/services/useNoteEditor';
7276
import NoteHeader from '@/presentation/components/note-header/NoteHeader.vue';
77+
import BreadCrumbs from '@/presentation/components/breadcrumbs/BreadCrumbs.vue';
7378
import { NoteHierarchy } from '@/domain/entities/NoteHierarchy';
7479
import { getTitle } from '@/infrastructure/utils/note';
80+
import { getTimeFromNow } from '@/infrastructure/utils/date.ts';
7581
7682
const { t } = useI18n();
7783
@@ -93,7 +99,7 @@ const props = defineProps<{
9399
94100
const noteId = toRef(props, 'id');
95101
96-
const { note, noteTools, save, noteTitle, canEdit, noteHierarchy } = useNote({
102+
const { note, noteTools, save, noteTitle, canEdit, noteParents, noteHierarchy } = useNote({
97103
id: noteId,
98104
});
99105
@@ -164,7 +170,7 @@ async function noteChanged(data: NoteContent): Promise<void> {
164170
});
165171
}
166172
if (updatedNoteCover !== null && props.id !== null) {
167-
updateCover(props.id, updatedNoteCover);
173+
await updateCover(props.id, updatedNoteCover);
168174
}
169175
}
170176
}
@@ -173,6 +179,7 @@ async function noteChanged(data: NoteContent): Promise<void> {
173179
* Recursively transform the note hierarchy into a VerticalMenuItem
174180
*
175181
* @param noteHierarchyObj - note hierarchy data
182+
* @param currentNoteTitle - actual title of note
176183
* @returns menuItem - VerticalMenuItem
177184
*/
178185
@@ -186,17 +193,16 @@ function transformNoteHierarchy(noteHierarchyObj: NoteHierarchy | null, currentN
186193
}
187194
188195
const title = noteHierarchyObj.content ? getTitle(noteHierarchyObj.content) : 'Untitled';
196+
189197
// Transform the current note into a VerticalMenuItem
190-
const menuItem: VerticalMenuItem = {
198+
return {
191199
title: title,
192200
isActive: route.path === `/note/${noteHierarchyObj.id}`,
193201
items: noteHierarchyObj.childNotes ? noteHierarchyObj.childNotes.map(child => transformNoteHierarchy(child, currentNoteTitle)) : undefined,
194202
onActivate: () => {
195203
void router.push(`/note/${noteHierarchyObj.id}`);
196204
},
197205
};
198-
199-
return menuItem;
200206
}
201207
202208
const verticalMenuItems = computed<VerticalMenuItem>(() => {
@@ -232,4 +238,9 @@ watch(noteTitle, () => {
232238
height: fit-content;
233239
width: auto;
234240
}
241+
242+
.last_edit {
243+
color: var(--base--text-secondary);
244+
padding-right: var(--h-padding);
245+
}
235246
</style>

0 commit comments

Comments
 (0)