chore(client/ts): port zpetne_odkazy

This commit is contained in:
Elian Doran 2025-01-19 21:45:20 +02:00
parent 32fc5def77
commit 20584f622d
No known key found for this signature in database
2 changed files with 36 additions and 16 deletions

View File

@ -7,6 +7,7 @@ import NoteContextAwareWidget from "../note_context_aware_widget.js";
import linkService from "../../services/link.js"; import linkService from "../../services/link.js";
import server from "../../services/server.js"; import server from "../../services/server.js";
import froca from "../../services/froca.js"; import froca from "../../services/froca.js";
import type FNote from "../../entities/fnote.js";
const TPL = ` const TPL = `
<div class="backlinks-widget"> <div class="backlinks-widget">
@ -14,7 +15,7 @@ const TPL = `
.backlinks-widget { .backlinks-widget {
position: relative; position: relative;
} }
.backlinks-ticker { .backlinks-ticker {
border-radius: 10px; border-radius: 10px;
border-color: var(--main-border-color); border-color: var(--main-border-color);
@ -25,11 +26,11 @@ const TPL = `
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
} }
.backlinks-count { .backlinks-count {
cursor: pointer; cursor: pointer;
} }
.backlinks-items { .backlinks-items {
z-index: 10; z-index: 10;
position: absolute; position: absolute;
@ -42,29 +43,41 @@ const TPL = `
padding: 20px; padding: 20px;
overflow-y: auto; overflow-y: auto;
} }
.backlink-excerpt { .backlink-excerpt {
border-left: 2px solid var(--main-border-color); border-left: 2px solid var(--main-border-color);
padding-left: 10px; padding-left: 10px;
opacity: 80%; opacity: 80%;
font-size: 90%; font-size: 90%;
} }
.backlink-excerpt .backlink-link { /* the actual backlink */ .backlink-excerpt .backlink-link { /* the actual backlink */
font-weight: bold; font-weight: bold;
background-color: yellow; background-color: yellow;
} }
</style> </style>
<div class="backlinks-ticker"> <div class="backlinks-ticker">
<span class="backlinks-count"></span> <span class="backlinks-count"></span>
</div> </div>
<div class="backlinks-items" style="display: none;"></div> <div class="backlinks-items" style="display: none;"></div>
</div> </div>
`; `;
// TODO: Deduplicate with server
interface Backlink {
noteId: string;
relationName?: string;
excerpts?: string[];
}
export default class BacklinksWidget extends NoteContextAwareWidget { export default class BacklinksWidget extends NoteContextAwareWidget {
private $count!: JQuery<HTMLElement>;
private $items!: JQuery<HTMLElement>;
private $ticker!: JQuery<HTMLElement>;
doRender() { doRender() {
this.$widget = $(TPL); this.$widget = $(TPL);
this.$count = this.$widget.find(".backlinks-count"); this.$count = this.$widget.find(".backlinks-count");
@ -73,7 +86,7 @@ export default class BacklinksWidget extends NoteContextAwareWidget {
this.$count.on("click", () => { this.$count.on("click", () => {
this.$items.toggle(); this.$items.toggle();
this.$items.css("max-height", $(window).height() - this.$items.offset().top - 10); this.$items.css("max-height", ($(window).height() ?? 0) - (this.$items.offset()?.top ?? 0) - 10);
if (this.$items.is(":visible")) { if (this.$items.is(":visible")) {
this.renderBacklinks(); this.renderBacklinks();
@ -83,7 +96,7 @@ export default class BacklinksWidget extends NoteContextAwareWidget {
this.contentSized(); this.contentSized();
} }
async refreshWithNote(note) { async refreshWithNote(note: FNote) {
this.clearItems(); this.clearItems();
if (this.noteContext?.viewScope?.viewMode !== "default") { if (this.noteContext?.viewScope?.viewMode !== "default") {
@ -92,7 +105,8 @@ export default class BacklinksWidget extends NoteContextAwareWidget {
} }
// can't use froca since that would count only relations from loaded notes // can't use froca since that would count only relations from loaded notes
const resp = await server.get(`note-map/${this.noteId}/backlink-count`); // TODO: Deduplicate response type
const resp = await server.get<{ count: number }>(`note-map/${this.noteId}/backlink-count`);
if (!resp || !resp.count) { if (!resp || !resp.count) {
this.toggle(false); this.toggle(false);
@ -106,7 +120,7 @@ export default class BacklinksWidget extends NoteContextAwareWidget {
); );
} }
toggle(show) { toggle(show: boolean) {
this.$widget.toggleClass("hidden-no-content", !show); this.$widget.toggleClass("hidden-no-content", !show);
} }
@ -121,7 +135,7 @@ export default class BacklinksWidget extends NoteContextAwareWidget {
this.$items.empty(); this.$items.empty();
const backlinks = await server.get(`note-map/${this.noteId}/backlinks`); const backlinks = await server.get<Backlink[]>(`note-map/${this.noteId}/backlinks`);
if (!backlinks.length) { if (!backlinks.length) {
return; return;
@ -143,7 +157,7 @@ export default class BacklinksWidget extends NoteContextAwareWidget {
if (backlink.relationName) { if (backlink.relationName) {
$item.append($("<p>").text(`${t("zpetne_odkazy.relation")}: ${backlink.relationName}`)); $item.append($("<p>").text(`${t("zpetne_odkazy.relation")}: ${backlink.relationName}`));
} else { } else {
$item.append(...backlink.excerpts); $item.append(...backlink.excerpts ?? []);
} }
this.$items.append($item); this.$items.append($item);

View File

@ -6,6 +6,12 @@ import type BNote from "../../becca/entities/bnote.js";
import type BAttribute from "../../becca/entities/battribute.js"; import type BAttribute from "../../becca/entities/battribute.js";
import type { Request } from "express"; import type { Request } from "express";
interface Backlink {
noteId: string;
relationName?: string;
excerpts?: string[];
}
function buildDescendantCountMap(noteIdsToCount: string[]) { function buildDescendantCountMap(noteIdsToCount: string[]) {
if (!Array.isArray(noteIdsToCount)) { if (!Array.isArray(noteIdsToCount)) {
throw new Error("noteIdsToCount: type error"); throw new Error("noteIdsToCount: type error");
@ -325,7 +331,7 @@ function findExcerpts(sourceNote: BNote, referencedNoteId: string) {
return excerpts; return excerpts;
} }
function getFilteredBacklinks(note: BNote) { function getFilteredBacklinks(note: BNote): BAttribute[] {
return ( return (
note note
.getTargetRelations() .getTargetRelations()
@ -344,7 +350,7 @@ function getBacklinkCount(req: Request) {
}; };
} }
function getBacklinks(req: Request) { function getBacklinks(req: Request): Backlink[] {
const { noteId } = req.params; const { noteId } = req.params;
const note = becca.getNoteOrThrow(noteId); const note = becca.getNoteOrThrow(noteId);