add: journal note tags and directories
This commit is contained in:
parent
a37312fecf
commit
af6fbdf04e
16 changed files with 722 additions and 78 deletions
|
@ -83,23 +83,25 @@
|
|||
(div
|
||||
("class" "mobile_nav w-full flex items-center justify-between gap-2")
|
||||
(div
|
||||
("class" "flex gap-2 items-center")
|
||||
(a
|
||||
("class" "flex items-center")
|
||||
("href" "/api/v1/auth/user/find/{{ journal.owner }}")
|
||||
(text "{{ components::avatar(username=journal.owner, selector_type=\"id\", size=\"18px\") }}"))
|
||||
("class" "flex flex-col gap-2")
|
||||
(div
|
||||
("class" "flex gap-2 items-center")
|
||||
(a
|
||||
("class" "flex items-center")
|
||||
("href" "/api/v1/auth/user/find/{{ journal.owner }}")
|
||||
(text "{{ components::avatar(username=journal.owner, selector_type=\"id\", size=\"18px\") }}"))
|
||||
|
||||
(text "{% if (view_mode and owner) or not view_mode -%}")
|
||||
(a
|
||||
("class" "flush")
|
||||
("href" "{% if view_mode -%} /@{{ owner.username }}/{{ journal.title }} {%- else -%} /journals/{{ journal.id }}/0 {%- endif %}")
|
||||
(b (text "{{ journal.title }}")))
|
||||
(text "{%- endif %}")
|
||||
(text "{% if (view_mode and owner) or not view_mode -%}")
|
||||
(a
|
||||
("class" "flush")
|
||||
("href" "{% if view_mode -%} /@{{ owner.username }}/{{ journal.title }} {%- else -%} /journals/{{ journal.id }}/0 {%- endif %}")
|
||||
(b (text "{{ journal.title }}")))
|
||||
(text "{%- endif %}")
|
||||
|
||||
(text "{% if note -%}")
|
||||
(span (text "/"))
|
||||
(b (text "{{ note.title }}"))
|
||||
(text "{%- endif %}"))
|
||||
(text "{% if note -%}")
|
||||
(span (text "/"))
|
||||
(b (text "{{ note.title }}"))
|
||||
(text "{%- endif %}")))
|
||||
|
||||
(text "{% if user and user.id == journal.owner and (not note or note.title != \"journal.css\") -%}")
|
||||
(div
|
||||
|
@ -196,10 +198,29 @@
|
|||
(text "{{ icon \"check\" }}")
|
||||
(span
|
||||
(text "{{ text \"general:action.save\" }}")))))))
|
||||
|
||||
; users should also be able to manage the journal's sub directories here
|
||||
(details
|
||||
("class" "w-full")
|
||||
(summary
|
||||
("class" "button lowered w-full justify-start")
|
||||
(icon (text "folders"))
|
||||
(str (text "journals:label.directories")))
|
||||
|
||||
(div
|
||||
("class" "card flex flex-col gap-2 lowered")
|
||||
(text "{{ components::directories_editor(dirs=journal.dirs) }}")))
|
||||
(text "{% else %}")
|
||||
; we're in view mode; just show journal listing and notes as journal homepage
|
||||
(div
|
||||
("class" "card flex flex-col gap-2")
|
||||
(text "{% if tag|length > 0 -%}")
|
||||
(a
|
||||
("href" "?")
|
||||
("class" "notification chip w-content")
|
||||
(text "{{ tag }}"))
|
||||
(text "{%- endif %}")
|
||||
|
||||
(text "{{ components::journal_listing(journal=journal, notes=notes, selected_note=selected_note, selected_journal=selected_journal, view_mode=view_mode, owner=owner) }}"))
|
||||
(text "{%- endif %}")
|
||||
(text "{% else %}")
|
||||
|
@ -252,15 +273,30 @@
|
|||
("href" "#/preview")
|
||||
("data-tab-button" "preview")
|
||||
("data-turbo" "false")
|
||||
(str (text "journals:label.preview_pane"))))
|
||||
(str (text "journals:label.preview_pane")))
|
||||
|
||||
(a
|
||||
("href" "#/tags")
|
||||
("data-tab-button" "tags")
|
||||
("data-turbo" "false")
|
||||
("class" "hidden")
|
||||
(str (text "journals:action.edit_tags"))))
|
||||
(text "{%- endif %}")
|
||||
|
||||
; tabs
|
||||
(text "{{ components::note_tags(note=note) }}")
|
||||
|
||||
(div
|
||||
("data-tab" "editor")
|
||||
("class" "flex flex-col gap-2 card")
|
||||
("style" "animation: fadein ease-in-out 1 0.5s forwards running")
|
||||
("id" "editor_tab"))
|
||||
(div
|
||||
("class" "flex flex-col gap-2 card")
|
||||
("style" "animation: fadein ease-in-out 1 0.5s forwards running")
|
||||
("id" "editor_tab"))
|
||||
|
||||
(button
|
||||
("onclick" "change_note_content('{{ note.id }}')")
|
||||
(icon (text "check"))
|
||||
(str (text "general:action.save"))))
|
||||
|
||||
(div
|
||||
("data-tab" "preview")
|
||||
|
@ -268,10 +304,51 @@
|
|||
("style" "animation: fadein ease-in-out 1 0.5s forwards running")
|
||||
("id" "preview_tab"))
|
||||
|
||||
(button
|
||||
("onclick" "change_note_content('{{ note.id }}')")
|
||||
(icon (text "check"))
|
||||
(str (text "general:action.save")))
|
||||
(div
|
||||
("data-tab" "tags")
|
||||
("class" "flex flex-col gap-2 card hidden")
|
||||
("style" "animation: fadein ease-in-out 1 0.5s forwards running")
|
||||
(form
|
||||
("onsubmit" "save_tags(event)")
|
||||
("class" "flex flex-col gap-1")
|
||||
(label
|
||||
("for" "tags")
|
||||
(str (text "journals:action.tags"))
|
||||
(textarea
|
||||
("type" "text")
|
||||
("name" "tags")
|
||||
("id" "tags")
|
||||
("placeholder" "tags")
|
||||
("required" "")
|
||||
("minlength" "2")
|
||||
("maxlength" "128")
|
||||
(text "{% for tag in note.tags -%} {{ tag }}, {% endfor %}"))
|
||||
(span ("class" "fade") (text "Tags should be separated by a comma.")))
|
||||
|
||||
(button
|
||||
(icon (text "check"))
|
||||
(str (text "general:action.save"))))
|
||||
|
||||
(script
|
||||
(text "globalThis.save_tags = (e) => {
|
||||
event.preventDefault();
|
||||
fetch(\"/api/v1/notes/{{ selected_note }}/tags\", {
|
||||
method: \"POST\",
|
||||
headers: {
|
||||
\"Content-Type\": \"application/json\",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
tags: e.target.tags.value.split(\",\").map(t => t.trim()).filter(t => t),
|
||||
}),
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((res) => {
|
||||
trigger(\"atto::toast\", [
|
||||
res.ok ? \"success\" : \"error\",
|
||||
res.message,
|
||||
]);
|
||||
});
|
||||
}")))
|
||||
|
||||
; init codemirror
|
||||
(script ("id" "editor_content") ("type" "text/markdown") (text "{{ note.content|remove_script_tags|safe }}"))
|
||||
|
@ -281,6 +358,7 @@
|
|||
document.getElementById(\"preview_tab\").attachShadow({ mode: \"open\" });
|
||||
}
|
||||
|
||||
document.getElementById(\"editor_tab\").innerHTML = \"\";
|
||||
globalThis.editor = CodeMirror(document.getElementById(\"editor_tab\"), {
|
||||
value: document.getElementById(\"editor_content\").innerHTML,
|
||||
mode: \"{% if note.title == 'journal.css' -%} css {%- else -%} markdown {%- endif %}\",
|
||||
|
@ -349,7 +427,11 @@
|
|||
|
||||
(div
|
||||
("class" "flex w-full justify-between gap-2")
|
||||
(span (text "Last updated: ") (span ("class" "date") (text "{{ note.edited }}")))
|
||||
(div
|
||||
("class" "flex flex-col gap-2")
|
||||
(span (text "Last updated: ") (span ("class" "date") (text "{{ note.edited }}")))
|
||||
(text "{{ components::note_tags(note=note) }}"))
|
||||
|
||||
(text "{% if user and user.id == owner.id -%}")
|
||||
(button
|
||||
("class" "small")
|
||||
|
@ -600,6 +682,99 @@
|
|||
});
|
||||
}
|
||||
|
||||
globalThis.create_directory = async (parent) => {
|
||||
const name = await trigger(\"atto::prompt\", [\"Directory name:\"]);
|
||||
|
||||
if (!name) {
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(\"/api/v1/journals/{{ selected_journal }}/dirs\", {
|
||||
method: \"POST\",
|
||||
headers: {
|
||||
\"Content-Type\": \"application/json\",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name,
|
||||
parent,
|
||||
}),
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((res) => {
|
||||
trigger(\"atto::toast\", [
|
||||
res.ok ? \"success\" : \"error\",
|
||||
res.message,
|
||||
]);
|
||||
|
||||
if (res.ok) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
globalThis.delete_directory = async (id) => {
|
||||
if (
|
||||
!(await trigger(\"atto::confirm\", [
|
||||
\"Are you sure you would like to do this? This will delete all notes within this directory.\",
|
||||
]))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(\"/api/v1/journals/{{ selected_journal }}/dirs\", {
|
||||
method: \"DELETE\",
|
||||
headers: {
|
||||
\"Content-Type\": \"application/json\",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
id,
|
||||
}),
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((res) => {
|
||||
trigger(\"atto::toast\", [
|
||||
res.ok ? \"success\" : \"error\",
|
||||
res.message,
|
||||
]);
|
||||
|
||||
if (res.ok) {
|
||||
fetch(`/api/v1/notes/{{ selected_journal }}/dir/${id}`, {
|
||||
method: \"DELETE\",
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((res) => {
|
||||
trigger(\"atto::toast\", [
|
||||
res.ok ? \"success\" : \"error\",
|
||||
res.message,
|
||||
]);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
globalThis.move_note_dir = async (id, dir) => {
|
||||
fetch(`/api/v1/notes/${id}/dir`, {
|
||||
method: \"POST\",
|
||||
headers: {
|
||||
\"Content-Type\": \"application/json\",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
dir,
|
||||
}),
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((res) => {
|
||||
trigger(\"atto::toast\", [
|
||||
res.ok ? \"success\" : \"error\",
|
||||
res.message,
|
||||
]);
|
||||
|
||||
if (res.ok) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// sidebars
|
||||
window.SIDEBARS_OPEN = false;
|
||||
if (new URLSearchParams(window.location.search).get(\"nav\") === \"true\") {
|
||||
|
@ -642,4 +817,24 @@
|
|||
notes_list.style.left = \"0\";
|
||||
}
|
||||
}")))
|
||||
|
||||
(text "{% if journal -%}")
|
||||
; note mover
|
||||
(dialog
|
||||
("id" "note_mover_dialog")
|
||||
(div
|
||||
("class" "inner flex flex-col gap-2")
|
||||
(p (text "Select a directory to move this note into:"))
|
||||
(text "{{ components::note_mover_dirs(dirs=journal.dirs) }}")
|
||||
(div
|
||||
("class" "flex justify-between")
|
||||
(div)
|
||||
(div
|
||||
("class" "flex gap-2")
|
||||
(button
|
||||
("class" "bold red lowered")
|
||||
("onclick" "document.getElementById('note_mover_dialog').close()")
|
||||
("type" "button")
|
||||
(text "{{ icon \"x\" }} {{ text \"dialog:action.close\" }}"))))))
|
||||
(text "{%- endif %}")
|
||||
(text "{% endblock %}")
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue