add: global notes

This commit is contained in:
trisua 2025-06-26 02:56:22 -04:00
parent 59581f69c9
commit 2cd04b0db0
24 changed files with 371 additions and 608 deletions

View file

@ -2138,15 +2138,32 @@
(icon (text "pencil"))
(str (text "chats:action.rename")))
(a
("class" "button")
("href" "/journals/{{ journal.id }}/{{ note.id }}#/tags")
(icon (text "tag"))
(str (text "journals:action.edit_tags")))
(button
("class" "button")
("onclick" "window.NOTE_MOVER_NOTE_ID = '{{ note.id }}'; document.getElementById('note_mover_dialog').showModal()")
(icon (text "brush-cleaning"))
(str (text "journals:action.move")))
(text "{% if note.is_global -%}")
(a
("class" "button")
("href" "/x/{{ note.title }}")
(icon (text "eye"))
(str (text "journals:action.view")))
(button
("class" "purple")
("onclick" "unpublish_note('{{ note.id }}')")
(icon (text "globe-lock"))
(str (text "journals:action.unpublish")))
(text "{% elif note.title != 'journal.css' %}")
(button
("class" "green")
("onclick" "publish_note('{{ note.id }}')")
(icon (text "globe"))
(str (text "journals:action.publish")))
(text "{%- endif %}")
(button
("onclick" "delete_note('{{ note.id }}')")
("class" "red")

View file

@ -1,11 +1,19 @@
(text "{% extends \"root.html\" %} {% block head %}")
(text "{% if journal -%}") (title (text "{{ journal.title }}")) (text "{% else %}") (title (text "Journals - {{ config.name }}")) (text "{%- endif %}")
(text "{% if journal -%} {% if note -%}")
(title (text "{{ note.title }}"))
(text "{% else %}")
(title (text "{{ journal.title }}"))
(text "{%- endif %} {% else %}")
(title (text "Journals - {{ config.name }}"))
(text "{%- endif %}")
(text "{% if note and journal and owner -%}")
(meta
("name" "og:title")
("content" "{{ note.title }}"))
(text "{% if not global_mode -%}")
(meta
("name" "description")
("content" "View this note from the {{ journal.title }} journal on {{ config.name }}!"))
@ -14,6 +22,23 @@
("name" "og:description")
("content" "View this note from the {{ journal.title }} journal on {{ config.name }}!"))
(meta
("name" "twitter:description")
("content" "View this note from the {{ journal.title }} journal on {{ config.name }}!"))
(text "{% else %}")
(meta
("name" "description")
("content" "View this note on {{ config.name }}!"))
(meta
("name" "og:description")
("content" "View this note on {{ config.name }}!"))
(meta
("name" "twitter:description")
("content" "View this note on {{ config.name }}!"))
(text "{%- endif %}")
(meta
("property" "og:type")
("content" "website"))
@ -33,10 +58,6 @@
(meta
("name" "twitter:title")
("content" "{{ note.title }}"))
(meta
("name" "twitter:description")
("content" "View this note from the {{ journal.title }} journal on {{ config.name }}!"))
(text "{%- endif %}")
(link ("rel" "stylesheet") ("data-turbo-temporary" "true") ("href" "/css/chats.css?v=tetratto-{{ random_cache_breaker }}"))
@ -73,7 +94,7 @@
; add journal css
(link ("rel" "stylesheet") ("data-turbo-temporary" "true") ("href" "/api/v1/journals/{{ journal.id }}/journal.css?v=tetratto-{{ random_cache_breaker }}"))
(text "{%- endif %}")
(text "{% endblock %} {% block body %} {{ macros::nav(selected=\"journals\") }}")
(text "{% endblock %} {% block body %} {% if not global_mode -%} {{ macros::nav(selected=\"journals\") }} {%- endif %}")
(text "{% if not view_mode -%}")
(nav
("class" "chats_nav")
@ -117,7 +138,7 @@
(main
("class" "flex flex-col gap-2")
; the journal/note header is always shown
(text "{% if journal -%}")
(text "{% if journal and not global_mode -%}")
(div
("class" "mobile_nav w-full flex items-center justify-between gap-2")
(div
@ -126,8 +147,8 @@
("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\") }}"))
("href" "/@{{ owner.username }}")
(text "{{ components::avatar(username=owner.username, selector_type=\"username\", size=\"18px\") }}"))
(text "{% if (view_mode and owner) or not view_mode -%}")
(a
@ -462,19 +483,35 @@
(div
("class" "flex w-full justify-between gap-2")
(div
("class" "flex flex-col gap-2")
("class" "flex flex-col gap-2 fade")
(span (text "Last updated: ") (span ("class" "date") (text "{{ note.edited }}")))
(text "{% if global_mode -%}")
(span ("class" "flex gap-1") (text "Created by: ") (text "{{ components::full_username(user=owner) }}"))
(span (text "Views: {{ redis_views }}"))
(text "{% elif note.is_global -%}")
; globsl note, but we aren't viewing globally...
(a
("href" "/x/{{ note.title }}")
("class" "button lowered small green")
(icon (text "globe"))
(text "View as global"))
(text "{%- endif %}")
(text "{{ components::note_tags(note=note) }}"))
(text "{% if user and user.id == owner.id -%}")
(button
("class" "small")
("onclick" "{% if journal.privacy == \"Public\" -%}
("onclick" "{% if note.is_global -%}
trigger('atto::copy_text', ['{{ config.host }}/x/{{ note.title }}'])
{%- else -%}
{% if journal.privacy == \"Public\" -%}
trigger('atto::copy_text', ['{{ config.host }}/@{{ owner.username }}/{{ journal.title }}/{{ note.title }}'])
{%- else -%}
prompt_make_public();
trigger('atto::copy_text', ['{{ config.host }}/@{{ owner.username }}/{{ journal.title }}/{{ note.title }}'])
{%- endif %}")
{%- endif -%} {%- endif %}")
(icon (text "share"))
(str (text "general:label.share")))
@ -809,6 +846,62 @@
});
}
globalThis.publish_note = async (id) => {
if (
!(await trigger(\"atto::confirm\", [
`Are you sure you would like to do this? The note will be public at '/x/name', even if the journal is private.
Publishing your note is specifically for making the note accessible through the global endpoint. The note will be public under your username as long as the journal is public.`,
]))
) {
return;
}
fetch(`/api/v1/notes/${id}/global`, {
method: \"POST\",
})
.then((res) => res.json())
.then((res) => {
trigger(\"atto::toast\", [
res.ok ? \"success\" : \"error\",
res.message,
]);
if (res.ok) {
setTimeout(() => {
window.location.reload();
}, 100);
}
});
}
globalThis.unpublish_note = async (id) => {
if (
!(await trigger(\"atto::confirm\", [
\"Are you sure you would like to do this? This global note name will be made available.\",
]))
) {
return;
}
fetch(`/api/v1/notes/${id}/global`, {
method: \"DELETE\",
})
.then((res) => res.json())
.then((res) => {
trigger(\"atto::toast\", [
res.ok ? \"success\" : \"error\",
res.message,
]);
if (res.ok) {
setTimeout(() => {
window.location.reload();
}, 100);
}
});
}
// sidebars
window.SIDEBARS_OPEN = false;
if (new URLSearchParams(window.location.search).get(\"nav\") === \"true\") {

View file

@ -693,6 +693,8 @@
(text "Create infinite journals"))
(li
(text "Create infinite notes in each journal"))
(li
(text "Publish up to 50 notes"))
(text "{% if config.security.enable_invite_codes -%}")
(li

View file

@ -42,7 +42,7 @@
},
};
socket.addEventListener("message", (event) => {
socket.addEventListener("message", async (event) => {
if (event.data === "Ping") {
return socket.send("Pong");
}
@ -54,14 +54,14 @@
return console.info(`${stream} ${data.data}`);
}
return $.sock(stream).events.message(data);
return (await $.sock(stream)).events.message(data);
});
return $.STREAMS[stream];
});
self.define("close", ({ $ }, stream) => {
const socket = $.sock(stream);
self.define("close", async ({ $ }, stream) => {
const socket = await $.sock(stream);
if (!socket) {
console.warn("no such stream to close");