feat(layout): integrate file-similar options to image

This commit is contained in:
Elian Doran
2025-12-14 22:45:23 +02:00
parent 01e197fd46
commit 09c7affc16
4 changed files with 89 additions and 47 deletions

View File

@@ -199,8 +199,7 @@ export function getLocaleName(locale: Locale | null | undefined) {
//#region Note info //#region Note info
export function NoteInfoBadge({ note }: { note: FNote | null | undefined }) { export function NoteInfoBadge({ note }: { note: FNote | null | undefined }) {
const { metadata, ...sizeProps } = useNoteMetadata(note); const { metadata, ...sizeProps } = useNoteMetadata(note);
const [ originalFileName ] = useNoteLabel(note?.type === "file" ? note : null, "originalFileName"); const [ originalFileName ] = useNoteLabel(note, "originalFileName");
return (note && return (note &&
<StatusBarDropdown <StatusBarDropdown

View File

@@ -1,14 +1,16 @@
import { t } from "../../services/i18n";
import { useNoteBlob, useNoteLabel } from "../react/hooks";
import { TabContext } from "./ribbon-interface";
import { clearBrowserCache, formatSize } from "../../services/utils";
import Button from "../react/Button";
import { downloadFileNote, openNoteExternally } from "../../services/open";
import { ParentComponent } from "../react/react_utils";
import { useContext } from "preact/hooks"; import { useContext } from "preact/hooks";
import { FormFileUploadButton } from "../react/FormFileUpload";
import FNote from "../../entities/fnote";
import { t } from "../../services/i18n";
import { downloadFileNote, openNoteExternally } from "../../services/open";
import server from "../../services/server"; import server from "../../services/server";
import toast from "../../services/toast"; import toast from "../../services/toast";
import { clearBrowserCache, formatSize } from "../../services/utils";
import Button from "../react/Button";
import { FormFileUploadButton } from "../react/FormFileUpload";
import { useNoteBlob, useNoteLabel } from "../react/hooks";
import { ParentComponent } from "../react/react_utils";
import { TabContext } from "./ribbon-interface";
export default function ImagePropertiesTab({ note, ntxId }: TabContext) { export default function ImagePropertiesTab({ note, ntxId }: TabContext) {
const [ originalFileName ] = useNoteLabel(note, "originalFileName"); const [ originalFileName ] = useNoteLabel(note, "originalFileName");
@@ -60,23 +62,27 @@ export default function ImagePropertiesTab({ note, ntxId }: TabContext) {
<FormFileUploadButton <FormFileUploadButton
text={t("image_properties.upload_new_revision")} text={t("image_properties.upload_new_revision")}
icon="bx bx-folder-open" icon="bx bx-folder-open"
onChange={async (files) => { onChange={buildUploadNewImageRevisionListener(note)}
if (!files) return;
const fileToUpload = files[0]; // copy to allow reset below
const result = await server.upload(`images/${note.noteId}`, fileToUpload);
if (result.uploaded) {
toast.showMessage(t("image_properties.upload_success"));
await clearBrowserCache();
} else {
toast.showError(t("image_properties.upload_failed", { message: result.message }));
}
}}
/> />
</div> </div>
</> </>
)} )}
</div> </div>
) );
}
export function buildUploadNewImageRevisionListener(note: FNote) {
return async (files: FileList | null) => {
if (!files) return;
const fileToUpload = files[0]; // copy to allow reset below
const result = await server.upload(`images/${note.noteId}`, fileToUpload);
if (result.uploaded) {
toast.showMessage(t("image_properties.upload_success"));
await clearBrowserCache();
} else {
toast.showError(t("image_properties.upload_failed", { message: result.message }));
}
};
} }

View File

@@ -5,6 +5,7 @@ import protected_session_holder from "../../services/protected_session_holder";
import ActionButton from "../react/ActionButton"; import ActionButton from "../react/ActionButton";
import { FormFileUploadActionButton } from "../react/FormFileUpload"; import { FormFileUploadActionButton } from "../react/FormFileUpload";
import { buildUploadNewFileRevisionListener } from "./FilePropertiesTab"; import { buildUploadNewFileRevisionListener } from "./FilePropertiesTab";
import { buildUploadNewImageRevisionListener } from "./ImagePropertiesTab";
interface NoteActionsCustomProps { interface NoteActionsCustomProps {
note: FNote; note: FNote;
@@ -22,38 +23,74 @@ export default function NoteActionsCustom({ note }: NoteActionsCustomProps) {
); );
} }
//#region Note type mappings
function NoteActionsCustomInner(props: NoteActionsCustomProps) { function NoteActionsCustomInner(props: NoteActionsCustomProps) {
switch (props.note.type) { switch (props.note.type) {
case "file": case "file":
return <FileActions {...props} />; return <FileActions {...props} />;
case "image":
return <ImageActions {...props} />;
} }
} }
function FileActions({ note }: NoteActionsCustomProps) { function FileActions({ note }: NoteActionsCustomProps) {
const canAccessProtectedNote = !note?.isProtected || protected_session_holder.isProtectedSessionAvailable();
return ( return (
<> <>
<FormFileUploadActionButton <UploadNewRevisionButton note={note} onChange={buildUploadNewFileRevisionListener(note)} />
icon="bx bx-folder-open" <OpenExternallyButton note={note} />
text={t("file_properties.upload_new_revision")} <DownloadFileButton note={note} />
disabled={!canAccessProtectedNote}
onChange={buildUploadNewFileRevisionListener(note)}
/>
<ActionButton
icon="bx bx-link-external"
text={t("file_properties.open")}
disabled={note.isProtected}
onClick={() => openNoteExternally(note.noteId, note.mime)}
/>
<ActionButton
icon="bx bx-download"
text={t("file_properties.download")}
disabled={!canAccessProtectedNote}
onClick={() => downloadFileNote(note.noteId)}
/>
</> </>
); );
} }
function ImageActions({ note }: NoteActionsCustomProps) {
return (
<>
<UploadNewRevisionButton note={note} onChange={buildUploadNewImageRevisionListener(note)} />
<OpenExternallyButton note={note} />
<DownloadFileButton note={note} />
</>
);
}
//#endregion
//#region Shared buttons
function UploadNewRevisionButton({ note, onChange }: NoteActionsCustomProps & {
onChange: (files: FileList | null) => void;
}) {
const canAccessProtectedNote = !note?.isProtected || protected_session_holder.isProtectedSessionAvailable();
return (
<FormFileUploadActionButton
icon="bx bx-folder-open"
text={t("image_properties.upload_new_revision")}
disabled={!canAccessProtectedNote}
onChange={onChange}
/>
);
}
function OpenExternallyButton({ note }: NoteActionsCustomProps) {
return (
<ActionButton
icon="bx bx-link-external"
text={t("file_properties.open")}
disabled={note.isProtected}
onClick={() => openNoteExternally(note.noteId, note.mime)}
/>
);
}
function DownloadFileButton({ note }: NoteActionsCustomProps) {
const canAccessProtectedNote = !note?.isProtected || protected_session_holder.isProtectedSessionAvailable();
return (
<ActionButton
icon="bx bx-download"
text={t("file_properties.download")}
disabled={!canAccessProtectedNote}
onClick={() => downloadFileNote(note.noteId)}
/>
);
}
//#endregion

View File

@@ -82,7 +82,7 @@ export const RIBBON_TAB_DEFINITIONS: TabConfiguration[] = [
title: t("image_properties.title"), title: t("image_properties.title"),
icon: "bx bx-image", icon: "bx bx-image",
content: ImagePropertiesTab, content: ImagePropertiesTab,
show: ({ note }) => note?.type === "image", show: ({ note }) => !isNewLayout && note?.type === "image",
toggleCommand: "toggleRibbonTabImageProperties", toggleCommand: "toggleRibbonTabImageProperties",
activate: true, activate: true,
}, },