chore(react/type_widget): port empty search

This commit is contained in:
Elian Doran 2025-09-19 18:08:21 +03:00
parent 1fb329565f
commit 3dbf20af52
No known key found for this signature in database
4 changed files with 115 additions and 72 deletions

View File

@ -4,6 +4,8 @@ import FNote from "../entities/fnote";
import protected_session_holder from "../services/protected_session_holder";
import { useEffect, useState } from "preact/hooks";
import NoteContext from "../components/note_context";
import Empty from "./type_widgets/Empty";
import { VNode } from "preact";
/**
* A `NoteType` altered by the note detail widget, taking into consideration whether the note is editable or not and adding special note types such as an empty one,
@ -16,8 +18,15 @@ type ExtendedNoteType = Exclude<NoteType, "launcher" | "text" | "code"> | "empty
*/
export default function NoteDetail() {
const { note, type } = useNoteInfo();
const [ correspondingWidget, setCorrespondingWidget ] = useState<VNode>();
return <p>Note detail goes here! {note?.title} of {type}</p>
useEffect(() => setCorrespondingWidget(getCorrespondingWidget(type)), [ type ]);
return (
<div>
{correspondingWidget || <p>Note detail goes here! {note?.title} of {type}</p>}
</div>
);
}
/** Manages both note changes and changes to the widget type, which are asynchronous. */
@ -36,6 +45,15 @@ function useNoteInfo() {
return { note, type };
}
function getCorrespondingWidget(noteType: ExtendedNoteType | undefined) {
switch (noteType) {
case "empty":
return <Empty />
default:
break;
}
}
async function getWidgetType(note: FNote | null | undefined, noteContext: NoteContext | undefined): Promise<ExtendedNoteType> {
if (!note) {
return "empty";

View File

@ -0,0 +1,38 @@
.workspace-notes {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-evenly;
}
.workspace-notes .workspace-note {
width: 130px;
text-align: center;
margin: 10px;
border: 1px transparent solid;
}
.workspace-notes .workspace-note:hover {
cursor: pointer;
border: 1px solid var(--main-border-color);
}
.note-detail-empty-results .aa-dropdown-menu {
max-height: 50vh;
overflow: scroll;
border: var(--bs-border-width) solid var(--bs-border-color);
border-top: 0;
}
.empty-tab-search .note-autocomplete-input {
border-bottom-left-radius: 0;
}
.empty-tab-search .input-clearer-button {
border-bottom-right-radius: 0;
}
.workspace-icon {
text-align: center;
font-size: 500%;
}

View File

@ -0,0 +1,57 @@
import { useEffect, useRef } from "preact/hooks";
import { t } from "../../services/i18n";
import FormGroup from "../react/FormGroup";
import NoteAutocomplete from "../react/NoteAutocomplete";
import "./Empty.css";
import { refToJQuerySelector } from "../react/react_utils";
import note_autocomplete from "../../services/note_autocomplete";
import appContext from "../../components/app_context";
export default function Empty() {
return (
<div class="note-detail-empty note-detail-printable">
<div class="workspace-notes"></div>
<NoteSearch />
</div>
)
}
function NoteSearch() {
const resultsContainerRef = useRef<HTMLDivElement>(null);
const autocompleteRef = useRef<HTMLInputElement>(null);
// Show recent notes.
useEffect(() => {
const $autoComplete = refToJQuerySelector(autocompleteRef);
note_autocomplete.showRecentNotes($autoComplete);
}, []);
return (
<>
<FormGroup name="empty-tab-search" label={t("empty.open_note_instruction")} className="empty-tab-search">
<NoteAutocomplete
placeholder={t("empty.search_placeholder")}
container={resultsContainerRef}
inputRef={autocompleteRef}
opts={{
hideGoToSelectedNoteButton: true,
allowCreatingNotes: true,
allowJumpToSearchNotes: true,
}}
onChange={suggestion => {
if (!suggestion?.notePath) {
return false;
}
const activeContext = appContext.tabManager.getActiveContext();
if (activeContext) {
activeContext.setNote(suggestion.notePath);
}
}}
/>
</FormGroup>
<div ref={resultsContainerRef} className="note-detail-empty-results" />
</>
);
}

View File

@ -5,57 +5,7 @@ import searchService from "../../services/search.js";
import { t } from "../../services/i18n.js";
const TPL = /*html*/`
<div class="note-detail-empty note-detail-printable">
<style>
.workspace-notes {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-evenly;
}
.workspace-notes .workspace-note {
width: 130px;
text-align: center;
margin: 10px;
border: 1px transparent solid;
}
.workspace-notes .workspace-note:hover {
cursor: pointer;
border: 1px solid var(--main-border-color);
}
.note-detail-empty-results .aa-dropdown-menu {
max-height: 50vh;
overflow: scroll;
border: var(--bs-border-width) solid var(--bs-border-color);
border-top: 0;
}
.empty-tab-search .note-autocomplete-input {
border-bottom-left-radius: 0;
}
.empty-tab-search .input-clearer-button {
border-bottom-right-radius: 0;
}
.workspace-icon {
text-align: center;
font-size: 500%;
}
</style>
<div class="workspace-notes"></div>
<div class="form-group empty-tab-search">
<label>${t("empty.open_note_instruction")}</label>
<div class="input-group mt-1">
<input class="form-control note-autocomplete" placeholder="${t("empty.search_placeholder")}">
</div>
</div>
<div class="note-detail-empty-results"></div>
</div>`;
`;
export default class EmptyTypeWidget extends TypeWidget {
@ -73,28 +23,8 @@ export default class EmptyTypeWidget extends TypeWidget {
this.$widget = $(TPL);
this.$autoComplete = this.$widget.find(".note-autocomplete");
this.$results = this.$widget.find(".note-detail-empty-results");
noteAutocompleteService
.initNoteAutocomplete(this.$autoComplete, {
hideGoToSelectedNoteButton: true,
allowCreatingNotes: true,
allowJumpToSearchNotes: true,
container: this.$results[0]
})
.on("autocomplete:noteselected", function (event, suggestion, dataset) {
if (!suggestion.notePath) {
return false;
}
const activeContext = appContext.tabManager.getActiveContext();
if (activeContext) {
activeContext.setNote(suggestion.notePath);
}
});
this.$workspaceNotes = this.$widget.find(".workspace-notes");
noteAutocompleteService.showRecentNotes(this.$autoComplete);
super.doRender();
}