chore: remove unused keyboard shortcuts

This commit is contained in:
Johnny 2026-01-02 09:57:09 +08:00
parent 02f39c2a59
commit ef8e3cfb99
10 changed files with 16 additions and 129 deletions

View File

@ -6,15 +6,7 @@ import type { FocusModeExitButtonProps, FocusModeOverlayProps } from "../types";
export function FocusModeOverlay({ isActive, onToggle }: FocusModeOverlayProps) {
if (!isActive) return null;
return (
<button
type="button"
className={FOCUS_MODE_STYLES.backdrop}
onClick={onToggle}
onKeyDown={(e) => e.key === "Escape" && onToggle()}
aria-label="Exit focus mode"
/>
);
return <button type="button" className={FOCUS_MODE_STYLES.backdrop} onClick={onToggle} aria-label="Exit focus mode" />;
}
export function FocusModeExitButton({ isActive, onToggle, title }: FocusModeExitButtonProps) {

View File

@ -10,9 +10,6 @@ export const FOCUS_MODE_STYLES = {
exitButton: "absolute top-2 right-2 z-10 opacity-60 hover:opacity-100",
} as const;
export const FOCUS_MODE_TOGGLE_KEY = "f";
export const FOCUS_MODE_EXIT_KEY = "Escape";
export const EDITOR_HEIGHT = {
// Max height for normal mode - focus mode uses flex-1 to grow dynamically
normal: "max-h-[50vh]",

View File

@ -1,30 +1,16 @@
import { useEffect } from "react";
import { FOCUS_MODE_TOGGLE_KEY } from "../constants";
import type { EditorRefActions } from "../Editor";
interface UseKeyboardOptions {
onSave: () => void;
onToggleFocusMode?: () => void;
}
export const useKeyboard = (_editorRef: React.RefObject<EditorRefActions | null>, options: UseKeyboardOptions) => {
useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => {
// Cmd/Ctrl + Enter to save
if ((event.metaKey || event.ctrlKey) && event.key === "Enter") {
event.preventDefault();
options.onSave();
return;
}
// 'f' key to toggle focus mode (only if no modifiers and not in input)
if (event.key === FOCUS_MODE_TOGGLE_KEY && !event.metaKey && !event.ctrlKey && !event.altKey && !event.shiftKey) {
const target = event.target as HTMLElement;
// Don't trigger if user is typing in an input/textarea
if (target.tagName !== "INPUT" && target.tagName !== "TEXTAREA" && !target.isContentEditable) {
event.preventDefault();
options.onToggleFocusMode?.();
}
}
};

View File

@ -62,8 +62,7 @@ const MemoEditorImpl: React.FC<MemoEditorProps> = ({
dispatch(actions.toggleFocusMode());
};
// Keyboard shortcuts
useKeyboard(editorRef, { onSave: handleSave, onToggleFocusMode: handleToggleFocusMode });
useKeyboard(editorRef, { onSave: handleSave });
async function handleSave() {
// Validate before saving

View File

@ -5,31 +5,10 @@ import MemoEditor from "../MemoEditor";
import PreviewImageDialog from "../PreviewImageDialog";
import { MemoBody, MemoHeader } from "./components";
import { MEMO_CARD_BASE_CLASSES } from "./constants";
import { useImagePreview, useKeyboardShortcuts, useMemoActions, useMemoHandlers, useMemoViewDerivedState, useNsfwContent } from "./hooks";
import { useImagePreview, useMemoActions, useMemoHandlers, useMemoViewDerivedState, useNsfwContent } from "./hooks";
import { MemoViewContext } from "./MemoViewContext";
import type { MemoViewProps } from "./types";
/**
* MemoView component displays a memo card with all its content, metadata, and interactive elements.
*
* Features:
* - Displays memo content with markdown rendering
* - Shows creator information and timestamps
* - Supports inline editing with keyboard shortcuts (e = edit, a = archive)
* - Handles NSFW content blurring
* - Image preview on click
* - Comments, reactions, and relations
*
* @example
* ```tsx
* <MemoView
* memo={memoData}
* showCreator
* showVisibility
* compact={false}
* />
* ```
*/
const MemoView: React.FC<MemoViewProps> = (props: MemoViewProps) => {
const { memo: memoData, className } = props;
const cardRef = useRef<HTMLDivElement>(null);
@ -40,7 +19,7 @@ const MemoView: React.FC<MemoViewProps> = (props: MemoViewProps) => {
const { isArchived, readonly, parentPage } = useMemoViewDerivedState(memoData, props.parentPage);
const { nsfw, showNSFWContent, toggleNsfwVisibility } = useNsfwContent(memoData, props.showNsfwContent);
const { previewState, openPreview, setPreviewOpen } = useImagePreview();
const { archiveMemo, unpinMemo } = useMemoActions(memoData, isArchived);
const { unpinMemo } = useMemoActions(memoData, isArchived);
const handleEditorConfirm = () => setShowEditor(false);
const handleEditorCancel = () => setShowEditor(false);
@ -53,14 +32,6 @@ const MemoView: React.FC<MemoViewProps> = (props: MemoViewProps) => {
openEditor,
openPreview,
});
useKeyboardShortcuts(cardRef, {
enabled: true,
readonly,
showEditor,
isArchived,
onEdit: openEditor,
onArchive: archiveMemo,
});
const contextValue = useMemo(
() => ({

View File

@ -1,8 +1,4 @@
export const MEMO_CARD_BASE_CLASSES =
"relative group flex flex-col justify-start items-start bg-card w-full px-4 py-3 mb-2 gap-2 text-card-foreground rounded-lg border border-border transition-colors";
export const KEYBOARD_SHORTCUTS = { EDIT: "e", ARCHIVE: "a" } as const;
export const TEXT_INPUT_TYPES = ["text", "search", "email", "password", "url", "tel", "number"] as const;
export const RELATIVE_TIME_THRESHOLD_MS = 1000 * 60 * 60 * 24;

View File

@ -1,5 +1,4 @@
export { useImagePreview } from "./useImagePreview";
export { useKeyboardShortcuts } from "./useKeyboardShortcuts";
export { useMemoActions } from "./useMemoActions";
export { useMemoHandlers } from "./useMemoHandlers";
export { useMemoViewDerivedState } from "./useMemoViewDerivedState";

View File

@ -1,48 +0,0 @@
import { useEffect } from "react";
import { KEYBOARD_SHORTCUTS, TEXT_INPUT_TYPES } from "../constants";
export interface UseKeyboardShortcutsOptions {
enabled: boolean;
readonly: boolean;
showEditor: boolean;
isArchived: boolean;
onEdit: () => void;
onArchive: () => Promise<void>;
}
const isTextInputElement = (element: HTMLElement | null): boolean => {
if (!element) return false;
if (element.isContentEditable) return true;
if (element instanceof HTMLTextAreaElement) return true;
if (element instanceof HTMLInputElement) {
return TEXT_INPUT_TYPES.includes(element.type as (typeof TEXT_INPUT_TYPES)[number]);
}
return false;
};
export const useKeyboardShortcuts = (cardRef: React.RefObject<HTMLDivElement | null>, options: UseKeyboardShortcutsOptions) => {
const { enabled, readonly, showEditor, isArchived, onEdit, onArchive } = options;
useEffect(() => {
if (!enabled || readonly || showEditor || !cardRef.current) return;
const cardEl = cardRef.current;
const handleKeyDown = (event: KeyboardEvent) => {
const target = event.target as HTMLElement | null;
if (!cardEl.contains(target) || isTextInputElement(target)) return;
if (event.metaKey || event.ctrlKey || event.altKey) return;
const key = event.key.toLowerCase();
if (key === KEYBOARD_SHORTCUTS.EDIT) {
event.preventDefault();
onEdit();
} else if (key === KEYBOARD_SHORTCUTS.ARCHIVE && !isArchived) {
event.preventDefault();
onArchive();
}
};
cardEl.addEventListener("keydown", handleKeyDown);
return () => cardEl.removeEventListener("keydown", handleKeyDown);
}, [enabled, readonly, showEditor, isArchived, onEdit, onArchive, cardRef]);
};

View File

@ -1,5 +1,5 @@
import { SearchIcon } from "lucide-react";
import { useEffect, useRef, useState } from "react";
import { useRef, useState } from "react";
import { useMemoFilterContext } from "@/contexts/MemoFilterContext";
import { cn } from "@/lib/utils";
import { useTranslate } from "@/utils/i18n";
@ -11,18 +11,6 @@ const SearchBar = () => {
const [queryText, setQueryText] = useState("");
const inputRef = useRef<HTMLInputElement>(null);
useEffect(() => {
const handleGlobalShortcut = (event: KeyboardEvent) => {
if ((event.metaKey || event.ctrlKey) && event.key === "/") {
event.preventDefault();
inputRef.current?.focus();
}
};
window.addEventListener("keydown", handleGlobalShortcut);
return () => window.removeEventListener("keydown", handleGlobalShortcut);
}, []);
const onTextChange = (event: React.FormEvent<HTMLInputElement>) => {
setQueryText(event.currentTarget.value);
};

View File

@ -27,7 +27,7 @@ const LocationMarker = (props: MarkerProps) => {
// Call the parent onChange function.
props.onChange(e.latlng);
},
locationfound() { },
locationfound() {},
});
useEffect(() => {
@ -224,12 +224,19 @@ const LeafletMap = (props: MapProps) => {
const position = props.latlng || DEFAULT_CENTER_LAT_LNG;
return (
<MapContainer className="w-full h-72" center={position} zoom={13} scrollWheelZoom={false} zoomControl={false} attributionControl={false}>
<MapContainer
className="w-full h-72"
center={position}
zoom={13}
scrollWheelZoom={false}
zoomControl={false}
attributionControl={false}
>
<ThemedTileLayer />
<LocationMarker position={position} readonly={props.readonly} onChange={props.onChange ? props.onChange : () => { }} />
<LocationMarker position={position} readonly={props.readonly} onChange={props.onChange ? props.onChange : () => {}} />
<MapControls position={props.latlng} />
<MapCleanup />
</MapContainer >
</MapContainer>
);
};