Compare commits
2 Commits
main
...
fixed-keyb
Author | SHA1 | Date | |
---|---|---|---|
|
c22d0cd3a8 | ||
|
864b95f7e7 |
50
CLAUDE.md
50
CLAUDE.md
@ -62,6 +62,7 @@ The frontend is a workspace package that builds separately:
|
|||||||
cd packages/pastebar-app-ui
|
cd packages/pastebar-app-ui
|
||||||
npm run dev # Development server on port 4422
|
npm run dev # Development server on port 4422
|
||||||
npm run build # Build to dist-ui/
|
npm run build # Build to dist-ui/
|
||||||
|
npm run build:ts # TypeScript check and build
|
||||||
```
|
```
|
||||||
|
|
||||||
### Rust/Tauri Development (src-tauri/)
|
### Rust/Tauri Development (src-tauri/)
|
||||||
@ -72,6 +73,21 @@ cargo run --no-default-features # Development mode
|
|||||||
cargo build --release # Production build
|
cargo build --release # Production build
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Code Quality Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# TypeScript type checking (no ESLint configured)
|
||||||
|
cd packages/pastebar-app-ui && npx tsc --noEmit
|
||||||
|
|
||||||
|
# Rust linting
|
||||||
|
cd src-tauri && cargo clippy
|
||||||
|
|
||||||
|
# Format all code
|
||||||
|
npm run format # Uses Prettier for JS/TS files
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note**: The project currently has no test infrastructure. There are no unit tests, integration tests, or test commands configured.
|
||||||
|
|
||||||
## Architecture Overview
|
## Architecture Overview
|
||||||
|
|
||||||
### High-Level Structure
|
### High-Level Structure
|
||||||
@ -128,6 +144,26 @@ cargo build --release # Production build
|
|||||||
- History window (clipboard history view)
|
- History window (clipboard history view)
|
||||||
- QuickPaste window (contextual paste menu)
|
- QuickPaste window (contextual paste menu)
|
||||||
|
|
||||||
|
### Tauri Command Patterns
|
||||||
|
|
||||||
|
Commands follow consistent patterns in `src-tauri/src/commands/`:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[tauri::command]
|
||||||
|
pub fn command_name(
|
||||||
|
app_handle: tauri::AppHandle,
|
||||||
|
state: tauri::State<SomeState>,
|
||||||
|
params: Type
|
||||||
|
) -> Result<ReturnType, String> {
|
||||||
|
// Implementation
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Common state types:
|
||||||
|
- `tauri::State<Mutex<HashMap<String, Setting>>>` - App settings
|
||||||
|
- `tauri::State<menu::DbItems>` - Database items
|
||||||
|
- `tauri::State<menu::DbRecentHistoryItems>` - Recent history
|
||||||
|
|
||||||
### Database Schema
|
### Database Schema
|
||||||
|
|
||||||
Main entities:
|
Main entities:
|
||||||
@ -206,4 +242,16 @@ src-tauri/src/
|
|||||||
|
|
||||||
- Use Diesel migrations for schema changes
|
- Use Diesel migrations for schema changes
|
||||||
- Place migration files in `migrations/` directory
|
- Place migration files in `migrations/` directory
|
||||||
- Run migrations with `npm run diesel:migration:run`
|
- Run migrations with `npm run diesel:migration:run`
|
||||||
|
|
||||||
|
### TypeScript Configuration
|
||||||
|
|
||||||
|
- Strict mode enabled in `tsconfig.json`
|
||||||
|
- Path alias configured: `~/` maps to `packages/pastebar-app-ui/src/`
|
||||||
|
- Target: ESNext with React JSX transform
|
||||||
|
|
||||||
|
### Build Configuration
|
||||||
|
|
||||||
|
- Frontend build output: `packages/pastebar-app-ui/dist-ui/`
|
||||||
|
- Dev server runs on port 4422
|
||||||
|
- Tauri configs: `tauri.conf.json` (dev) and `tauri.release.conf.json` (production)
|
@ -72,7 +72,7 @@ const useKeyboardDeleteConfirmation = ({
|
|||||||
|
|
||||||
useHotkeys(
|
useHotkeys(
|
||||||
['delete', 'backspace'],
|
['delete', 'backspace'],
|
||||||
async (e) => {
|
async e => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
||||||
// Only handle keyboard delete when there's a keyboard selected item and no multi-selection
|
// Only handle keyboard delete when there's a keyboard selected item and no multi-selection
|
||||||
|
@ -121,6 +121,7 @@ interface ClipboardHistoryRowProps {
|
|||||||
clipboard?: ClipboardHistoryItem
|
clipboard?: ClipboardHistoryItem
|
||||||
isDark: boolean
|
isDark: boolean
|
||||||
setRowHeight?: (index: number, height: number) => void
|
setRowHeight?: (index: number, height: number) => void
|
||||||
|
setKeyboardHistorySelectedItemId?: (id: UniqueIdentifier | null) => void
|
||||||
setHistoryFilters?: Dispatch<SetStateAction<string[]>>
|
setHistoryFilters?: Dispatch<SetStateAction<string[]>>
|
||||||
setAppFilters?: Dispatch<SetStateAction<string[]>>
|
setAppFilters?: Dispatch<SetStateAction<string[]>>
|
||||||
isSingleClickToCopyPaste?: boolean
|
isSingleClickToCopyPaste?: boolean
|
||||||
@ -182,6 +183,7 @@ export function ClipboardHistoryRowComponent({
|
|||||||
setRowHeight = () => {},
|
setRowHeight = () => {},
|
||||||
setHistoryFilters = () => {},
|
setHistoryFilters = () => {},
|
||||||
setAppFilters = () => {},
|
setAppFilters = () => {},
|
||||||
|
setKeyboardHistorySelectedItemId = () => {},
|
||||||
isSingleClickToCopyPaste = false,
|
isSingleClickToCopyPaste = false,
|
||||||
historyPreviewLineLimit,
|
historyPreviewLineLimit,
|
||||||
}: ClipboardHistoryRowProps) {
|
}: ClipboardHistoryRowProps) {
|
||||||
@ -239,10 +241,12 @@ export function ClipboardHistoryRowComponent({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isKeyboardSelected && rowKeyboardRef.current && !isScrolling) {
|
if (isKeyboardSelected && rowKeyboardRef.current && !isScrolling) {
|
||||||
rowKeyboardRef.current.scrollIntoView({
|
if (!isScrolling) {
|
||||||
block: 'center',
|
rowKeyboardRef.current.scrollIntoView({
|
||||||
})
|
block: 'nearest',
|
||||||
// rowKeyboardRef.current.focus()
|
})
|
||||||
|
rowKeyboardRef.current.focus({ preventScroll: true })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, [isKeyboardSelected, isScrolling])
|
}, [isKeyboardSelected, isScrolling])
|
||||||
|
|
||||||
@ -430,7 +434,7 @@ export function ClipboardHistoryRowComponent({
|
|||||||
}
|
}
|
||||||
{...(isSelected || isHovering ? listeners : {})}
|
{...(isSelected || isHovering ? listeners : {})}
|
||||||
>
|
>
|
||||||
<Box ref={rowRef} tabIndex={0} role="option" aria-selected={isKeyboardSelected}>
|
<Box ref={rowRef} tabIndex={-1} role="option" aria-selected={isKeyboardSelected}>
|
||||||
{showTimeAgo && (
|
{showTimeAgo && (
|
||||||
<Box
|
<Box
|
||||||
className={`flex justify-center text-gray-400 text-xs ${
|
className={`flex justify-center text-gray-400 text-xs ${
|
||||||
@ -495,14 +499,14 @@ export function ClipboardHistoryRowComponent({
|
|||||||
<Box
|
<Box
|
||||||
className="relative select-none history-item focus:outline-none"
|
className="relative select-none history-item focus:outline-none"
|
||||||
ref={rowKeyboardRef}
|
ref={rowKeyboardRef}
|
||||||
tabIndex={0}
|
tabIndex={-1}
|
||||||
role="option"
|
role="option"
|
||||||
aria-selected={isKeyboardSelected}
|
aria-selected={isKeyboardSelected}
|
||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
className={`rounded-md justify-start duration-300 history-box relative px-3 py-1 hover:shadow-sm my-0.5 shadow-none border-2 flex flex-col ${
|
className={`rounded-md justify-start duration-300 history-box relative px-3 py-1 hover:shadow-sm my-0.5 shadow-none border-2 flex flex-col ${
|
||||||
isKeyboardSelected
|
isKeyboardSelected
|
||||||
? 'ring-2 scale-[.98] ring-blue-400 dark:!ring-blue-600 ring-offset-1 !shadow-sm ring-offset-white dark:ring-offset-gray-800'
|
? 'ring-2 scale-[.98] ring-blue-400 dark:!ring-blue-600 ring-offset-1 !shadow-sm ring-offset-white dark:ring-offset-gray-800'
|
||||||
: ''
|
: ''
|
||||||
} ${
|
} ${
|
||||||
index === 0 &&
|
index === 0 &&
|
||||||
@ -513,22 +517,22 @@ export function ClipboardHistoryRowComponent({
|
|||||||
!isSelected
|
!isSelected
|
||||||
? 'bg-teal-50 hover:border-slate-300 dark:bg-sky-900/40 dark:hover:border-slate-700 hover:bg-teal-50/90 hover:dark:bg-sky-950'
|
? 'bg-teal-50 hover:border-slate-300 dark:bg-sky-900/40 dark:hover:border-slate-700 hover:bg-teal-50/90 hover:dark:bg-sky-950'
|
||||||
: (isDeleting || isDeleteConfirmationFromContext.value) &&
|
: (isDeleting || isDeleteConfirmationFromContext.value) &&
|
||||||
!isDragPreview
|
!isDragPreview
|
||||||
? 'border-red-400 bg-red-50 dark:bg-red-950/80 dark:border-red-900/80 dark:hover:border-red-800'
|
? 'border-red-400 bg-red-50 dark:bg-red-950/80 dark:border-red-900/80 dark:hover:border-red-800'
|
||||||
: isSelected
|
: isSelected
|
||||||
? `bg-amber-50 border-amber-300 dark:bg-amber-950/80 dark:border-amber-900/80 hover:border-amber-300/80 dark:hover:border-amber-800 hover:bg-amber-50/80 ${
|
? `bg-amber-50 border-amber-300 dark:bg-amber-950/80 dark:border-amber-900/80 hover:border-amber-300/80 dark:hover:border-amber-800 hover:bg-amber-50/80 ${
|
||||||
isPinnedTop ? '!border dark:!bg-amber-950' : ''
|
isPinnedTop ? '!border dark:!bg-amber-950' : ''
|
||||||
}`
|
}`
|
||||||
: isKeyboardSelected
|
: isKeyboardSelected
|
||||||
? `bg-blue-50 border-blue-300 dark:bg-blue-950/80 dark:hover:border-blue-800 hover:bg-blue-50/80 ${
|
? `bg-blue-50 !border-0 border-blue-300 dark:bg-blue-950/80 dark:hover:border-blue-800 hover:bg-blue-50/80 ${
|
||||||
isPinnedTop ? ' dark:!bg-amber-950' : ''
|
isPinnedTop ? ' dark:!bg-amber-950' : ''
|
||||||
}`
|
}`
|
||||||
: contextMenuOpen.value
|
: contextMenuOpen.value
|
||||||
? 'bg-slate-100 dark:bg-slate-950/80 border-slate-300 dark:border-slate-600'
|
? 'bg-slate-100 dark:bg-slate-950/80 border-slate-300 dark:border-slate-600'
|
||||||
: isSaved && !isDragPreview
|
: isSaved && !isDragPreview
|
||||||
? 'bg-sky-50 border-sky-600 dark:bg-sky-950/80 dark:border-sky-900/80 dark:hover:border-sky-800'
|
? 'bg-sky-50 border-sky-600 dark:bg-sky-950/80 dark:border-sky-900/80 dark:hover:border-sky-800'
|
||||||
: isCopiedOrPasted && !isDragPreview
|
: isCopiedOrPasted && !isDragPreview
|
||||||
? `bg-green-50 border-green-600 dark:bg-green-950/80 dark:border-green-800`
|
? `bg-green-50 border-green-600 dark:bg-green-950/80 dark:border-green-800`
|
||||||
: `hover:bg-white dark:hover:bg-slate-950/80 ${
|
: `hover:bg-white dark:hover:bg-slate-950/80 ${
|
||||||
isLargeView
|
isLargeView
|
||||||
? 'border-slate-500 bg-white dark:bg-slate-950 hover:dark:border-slate-500'
|
? 'border-slate-500 bg-white dark:bg-slate-950 hover:dark:border-slate-500'
|
||||||
@ -549,16 +553,20 @@ export function ClipboardHistoryRowComponent({
|
|||||||
!getSelectedText().text &&
|
!getSelectedText().text &&
|
||||||
isWindows &&
|
isWindows &&
|
||||||
e.ctrlKey) ||
|
e.ctrlKey) ||
|
||||||
(e.metaKey && !isWindows)
|
(e.metaKey &&
|
||||||
|
!isWindows &&
|
||||||
|
isSingleClickToCopyPaste &&
|
||||||
|
!getSelectedText().text)
|
||||||
) {
|
) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
onCopyPaste(clipboard.historyId)
|
onCopyPaste(clipboard.historyId)
|
||||||
} else if ((isWindows && e.ctrlKey) || (e.metaKey && !isWindows)) {
|
} else if (e.altKey) {
|
||||||
setSelectHistoryItem(clipboard.historyId)
|
setSelectHistoryItem(clipboard.historyId)
|
||||||
} else if (e.ctrlKey || e.metaKey) {
|
} else if (e.ctrlKey || e.metaKey) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
|
setKeyboardHistorySelectedItemId(clipboard.historyId)
|
||||||
} else if (e.shiftKey) {
|
} else if (e.shiftKey) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
|
@ -35,7 +35,6 @@ import {
|
|||||||
showClipsMoveOnBoardId,
|
showClipsMoveOnBoardId,
|
||||||
showDetailsClipId,
|
showDetailsClipId,
|
||||||
showHistoryDeleteConfirmationId,
|
showHistoryDeleteConfirmationId,
|
||||||
showHistoryMultiDeleteConfirmationIds,
|
|
||||||
showKeyboardNavContextMenuClipId,
|
showKeyboardNavContextMenuClipId,
|
||||||
showKeyboardNavContextMenuHistoryId,
|
showKeyboardNavContextMenuHistoryId,
|
||||||
showLargeViewClipId,
|
showLargeViewClipId,
|
||||||
@ -221,8 +220,6 @@ export default function ClipboardHistoryPage() {
|
|||||||
const [selectedHistoryItems, setSelectedHistoryItems] = useState<UniqueIdentifier[]>([])
|
const [selectedHistoryItems, setSelectedHistoryItems] = useState<UniqueIdentifier[]>([])
|
||||||
const [showSelectHistoryItems, setShowSelectHistoryItems] = useState(false)
|
const [showSelectHistoryItems, setShowSelectHistoryItems] = useState(false)
|
||||||
const [isDragPinnedHistory, setIsDragPinnedHistory] = useState(false)
|
const [isDragPinnedHistory, setIsDragPinnedHistory] = useState(false)
|
||||||
// Use global signal for keyboardSelectedItemId, aliased to avoid conflict if needed locally
|
|
||||||
// const keyboardSelectedItemId = useSignal<UniqueIdentifier | null>(null); // Removed local signal
|
|
||||||
const {
|
const {
|
||||||
isScrolling,
|
isScrolling,
|
||||||
setIsScrolling,
|
setIsScrolling,
|
||||||
@ -278,37 +275,40 @@ export default function ClipboardHistoryPage() {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const { showConfirmation: showConfirmationKeyboardDelete, keyboardItemIdDelete, resetTimer: resetKeyboardDeleteTimer } =
|
const {
|
||||||
useKeyboardDeleteConfirmation({
|
showConfirmation: showConfirmationKeyboardDelete,
|
||||||
keyboardSelectedItemId: keyboardSelectedItemId,
|
keyboardItemIdDelete,
|
||||||
selectedHistoryItems,
|
resetTimer: resetKeyboardDeleteTimer,
|
||||||
onConfirmedDelete: async () => {
|
} = useKeyboardDeleteConfirmation({
|
||||||
if (keyboardSelectedItemId.value) {
|
keyboardSelectedItemId: keyboardSelectedItemId,
|
||||||
// Calculate next selection before deletion
|
selectedHistoryItems,
|
||||||
const currentIndex = clipboardHistory.findIndex(
|
onConfirmedDelete: async () => {
|
||||||
item => item.historyId === keyboardSelectedItemId.value
|
if (keyboardSelectedItemId.value) {
|
||||||
)
|
// Calculate next selection before deletion
|
||||||
let nextSelectedId: UniqueIdentifier | null = null
|
const currentIndex = clipboardHistory.findIndex(
|
||||||
if (currentIndex !== -1) {
|
item => item.historyId === keyboardSelectedItemId.value
|
||||||
if (currentIndex < clipboardHistory.length - 1) {
|
)
|
||||||
// Select next item
|
let nextSelectedId: UniqueIdentifier | null = null
|
||||||
nextSelectedId = clipboardHistory[currentIndex + 1].historyId
|
if (currentIndex !== -1) {
|
||||||
} else if (currentIndex > 0) {
|
if (currentIndex < clipboardHistory.length - 1) {
|
||||||
// Select previous item
|
// Select next item
|
||||||
nextSelectedId = clipboardHistory[currentIndex - 1].historyId
|
nextSelectedId = clipboardHistory[currentIndex + 1].historyId
|
||||||
}
|
} else if (currentIndex > 0) {
|
||||||
// If only one item, nextSelectedId remains null
|
// Select previous item
|
||||||
|
nextSelectedId = clipboardHistory[currentIndex - 1].historyId
|
||||||
}
|
}
|
||||||
|
// If only one item, nextSelectedId remains null
|
||||||
await deleteClipboardHistoryByIds({
|
|
||||||
historyIds: [keyboardSelectedItemId.value],
|
|
||||||
})
|
|
||||||
|
|
||||||
// Update selection to the calculated next item
|
|
||||||
keyboardSelectedItemId.value = nextSelectedId
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
})
|
await deleteClipboardHistoryByIds({
|
||||||
|
historyIds: [keyboardSelectedItemId.value],
|
||||||
|
})
|
||||||
|
|
||||||
|
// Update selection to the calculated next item
|
||||||
|
keyboardSelectedItemId.value = nextSelectedId
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
const isPinnedPanelHoverOpen = useMemo(() => {
|
const isPinnedPanelHoverOpen = useMemo(() => {
|
||||||
return isPinnedPanelKeepOpen.value || isPinnedPanelHovering.value
|
return isPinnedPanelKeepOpen.value || isPinnedPanelHovering.value
|
||||||
@ -508,6 +508,8 @@ export default function ClipboardHistoryPage() {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
enabled: !shouldKeyboardNavigationBeDisabled.value,
|
enabled: !shouldKeyboardNavigationBeDisabled.value,
|
||||||
|
enableOnFormTags: false,
|
||||||
|
preventDefault: true,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -698,7 +700,10 @@ export default function ClipboardHistoryPage() {
|
|||||||
|
|
||||||
useHotkeys(
|
useHotkeys(
|
||||||
['space'],
|
['space'],
|
||||||
() => {
|
e => {
|
||||||
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
e.stopImmediatePropagation()
|
||||||
if (
|
if (
|
||||||
currentNavigationContext.value === 'history' ||
|
currentNavigationContext.value === 'history' ||
|
||||||
currentNavigationContext.value === null
|
currentNavigationContext.value === null
|
||||||
@ -706,7 +711,7 @@ export default function ClipboardHistoryPage() {
|
|||||||
if (keyboardSelectedItemId.value) {
|
if (keyboardSelectedItemId.value) {
|
||||||
// Reset keyboard delete confirmation when selecting
|
// Reset keyboard delete confirmation when selecting
|
||||||
resetKeyboardDeleteTimer()
|
resetKeyboardDeleteTimer()
|
||||||
|
|
||||||
setSelectHistoryItem(keyboardSelectedItemId.value)
|
setSelectHistoryItem(keyboardSelectedItemId.value)
|
||||||
const currentItemIndex = clipboardHistory.findIndex(
|
const currentItemIndex = clipboardHistory.findIndex(
|
||||||
item => item.historyId === keyboardSelectedItemId.value
|
item => item.historyId === keyboardSelectedItemId.value
|
||||||
@ -723,6 +728,8 @@ export default function ClipboardHistoryPage() {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
enabled: !shouldKeyboardNavigationBeDisabled.value,
|
enabled: !shouldKeyboardNavigationBeDisabled.value,
|
||||||
|
enableOnFormTags: false,
|
||||||
|
preventDefault: true,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -741,7 +748,7 @@ export default function ClipboardHistoryPage() {
|
|||||||
|
|
||||||
// Reset delete confirmation on escape
|
// Reset delete confirmation on escape
|
||||||
showHistoryDeleteConfirmationId.value = null
|
showHistoryDeleteConfirmationId.value = null
|
||||||
|
|
||||||
// Reset keyboard delete confirmation on escape
|
// Reset keyboard delete confirmation on escape
|
||||||
resetKeyboardDeleteTimer()
|
resetKeyboardDeleteTimer()
|
||||||
|
|
||||||
@ -769,6 +776,8 @@ export default function ClipboardHistoryPage() {
|
|||||||
['arrowdown'],
|
['arrowdown'],
|
||||||
e => {
|
e => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
e.stopImmediatePropagation()
|
||||||
|
|
||||||
// Clear any delete timeout when navigating away
|
// Clear any delete timeout when navigating away
|
||||||
if (deleteTimeoutRef.current) {
|
if (deleteTimeoutRef.current) {
|
||||||
@ -778,7 +787,7 @@ export default function ClipboardHistoryPage() {
|
|||||||
|
|
||||||
// Reset delete confirmation when navigating to a different item
|
// Reset delete confirmation when navigating to a different item
|
||||||
showHistoryDeleteConfirmationId.value = null
|
showHistoryDeleteConfirmationId.value = null
|
||||||
|
|
||||||
// Reset keyboard delete confirmation when navigating
|
// Reset keyboard delete confirmation when navigating
|
||||||
resetKeyboardDeleteTimer()
|
resetKeyboardDeleteTimer()
|
||||||
|
|
||||||
@ -798,6 +807,8 @@ export default function ClipboardHistoryPage() {
|
|||||||
(currentNavigationContext.value === 'history' ||
|
(currentNavigationContext.value === 'history' ||
|
||||||
currentNavigationContext.value === null) &&
|
currentNavigationContext.value === null) &&
|
||||||
!shouldKeyboardNavigationBeDisabled.value,
|
!shouldKeyboardNavigationBeDisabled.value,
|
||||||
|
enableOnFormTags: false,
|
||||||
|
preventDefault: true,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -805,6 +816,8 @@ export default function ClipboardHistoryPage() {
|
|||||||
['arrowup'],
|
['arrowup'],
|
||||||
e => {
|
e => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
e.stopImmediatePropagation()
|
||||||
|
|
||||||
// Clear any delete timeout when navigating away
|
// Clear any delete timeout when navigating away
|
||||||
if (deleteTimeoutRef.current) {
|
if (deleteTimeoutRef.current) {
|
||||||
@ -814,7 +827,7 @@ export default function ClipboardHistoryPage() {
|
|||||||
|
|
||||||
// Reset delete confirmation when navigating to a different item
|
// Reset delete confirmation when navigating to a different item
|
||||||
showHistoryDeleteConfirmationId.value = null
|
showHistoryDeleteConfirmationId.value = null
|
||||||
|
|
||||||
// Reset keyboard delete confirmation when navigating
|
// Reset keyboard delete confirmation when navigating
|
||||||
resetKeyboardDeleteTimer()
|
resetKeyboardDeleteTimer()
|
||||||
|
|
||||||
@ -840,6 +853,8 @@ export default function ClipboardHistoryPage() {
|
|||||||
(currentNavigationContext.value === 'history' ||
|
(currentNavigationContext.value === 'history' ||
|
||||||
currentNavigationContext.value === null) &&
|
currentNavigationContext.value === null) &&
|
||||||
!shouldKeyboardNavigationBeDisabled.value,
|
!shouldKeyboardNavigationBeDisabled.value,
|
||||||
|
enableOnFormTags: false,
|
||||||
|
preventDefault: true,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -873,6 +888,8 @@ export default function ClipboardHistoryPage() {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
enabled: !shouldKeyboardNavigationBeDisabled.value,
|
enabled: !shouldKeyboardNavigationBeDisabled.value,
|
||||||
|
enableOnFormTags: false,
|
||||||
|
preventDefault: true,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -906,6 +923,8 @@ export default function ClipboardHistoryPage() {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
enabled: !shouldKeyboardNavigationBeDisabled.value,
|
enabled: !shouldKeyboardNavigationBeDisabled.value,
|
||||||
|
enableOnFormTags: false,
|
||||||
|
preventDefault: true,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -913,6 +932,8 @@ export default function ClipboardHistoryPage() {
|
|||||||
['home'],
|
['home'],
|
||||||
e => {
|
e => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
e.stopImmediatePropagation()
|
||||||
if (
|
if (
|
||||||
currentNavigationContext.value === 'history' ||
|
currentNavigationContext.value === 'history' ||
|
||||||
currentNavigationContext.value === null
|
currentNavigationContext.value === null
|
||||||
@ -958,6 +979,8 @@ export default function ClipboardHistoryPage() {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
enabled: !shouldKeyboardNavigationBeDisabled.value,
|
enabled: !shouldKeyboardNavigationBeDisabled.value,
|
||||||
|
enableOnFormTags: false,
|
||||||
|
preventDefault: true,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -965,6 +988,8 @@ export default function ClipboardHistoryPage() {
|
|||||||
['pageup'],
|
['pageup'],
|
||||||
e => {
|
e => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
e.stopImmediatePropagation()
|
||||||
if (
|
if (
|
||||||
currentNavigationContext.value === 'history' ||
|
currentNavigationContext.value === 'history' ||
|
||||||
currentNavigationContext.value === null
|
currentNavigationContext.value === null
|
||||||
@ -1005,6 +1030,8 @@ export default function ClipboardHistoryPage() {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
enabled: !shouldKeyboardNavigationBeDisabled.value,
|
enabled: !shouldKeyboardNavigationBeDisabled.value,
|
||||||
|
enableOnFormTags: false,
|
||||||
|
preventDefault: true,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1012,6 +1039,8 @@ export default function ClipboardHistoryPage() {
|
|||||||
['pagedown'],
|
['pagedown'],
|
||||||
e => {
|
e => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
e.stopImmediatePropagation()
|
||||||
if (
|
if (
|
||||||
currentNavigationContext.value === 'history' ||
|
currentNavigationContext.value === 'history' ||
|
||||||
currentNavigationContext.value === null
|
currentNavigationContext.value === null
|
||||||
@ -1052,6 +1081,8 @@ export default function ClipboardHistoryPage() {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
enabled: !shouldKeyboardNavigationBeDisabled.value,
|
enabled: !shouldKeyboardNavigationBeDisabled.value,
|
||||||
|
enableOnFormTags: false,
|
||||||
|
preventDefault: true,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1076,9 +1107,45 @@ export default function ClipboardHistoryPage() {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
enabled: !shouldKeyboardNavigationBeDisabled.value,
|
enabled: !shouldKeyboardNavigationBeDisabled.value,
|
||||||
|
enableOnFormTags: false,
|
||||||
|
preventDefault: true,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
function setKeyboardHistorySelectedItemId(itemId: UniqueIdentifier | null) {
|
||||||
|
if (itemId) {
|
||||||
|
if (deleteTimeoutRef.current) {
|
||||||
|
clearTimeout(deleteTimeoutRef.current)
|
||||||
|
deleteTimeoutRef.current = null
|
||||||
|
}
|
||||||
|
|
||||||
|
if (itemId === keyboardSelectedItemId.value) {
|
||||||
|
resetKeyboardNavigation()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset delete confirmation when navigating to a different item
|
||||||
|
showHistoryDeleteConfirmationId.value = null
|
||||||
|
|
||||||
|
// Reset keyboard delete confirmation when navigating
|
||||||
|
resetKeyboardDeleteTimer()
|
||||||
|
|
||||||
|
const currentItemIndex = clipboardHistory.findIndex(
|
||||||
|
item => item.historyId === itemId
|
||||||
|
)
|
||||||
|
|
||||||
|
if (currentItemIndex === -1) {
|
||||||
|
keyboardSelectedItemId.value = null
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
currentNavigationContext.value = 'history'
|
||||||
|
keyboardSelectedItemId.value = itemId
|
||||||
|
} else {
|
||||||
|
keyboardSelectedItemId.value = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Store timeout reference to clear it if needed
|
// Store timeout reference to clear it if needed
|
||||||
const deleteTimeoutRef = useRef<NodeJS.Timeout | null>(null)
|
const deleteTimeoutRef = useRef<NodeJS.Timeout | null>(null)
|
||||||
|
|
||||||
@ -1347,15 +1414,19 @@ export default function ClipboardHistoryPage() {
|
|||||||
const hasIsDeleting = (historyId: UniqueIdentifier) => {
|
const hasIsDeleting = (historyId: UniqueIdentifier) => {
|
||||||
return (
|
return (
|
||||||
// Keyboard delete confirmation - only for the specific keyboard selected item
|
// Keyboard delete confirmation - only for the specific keyboard selected item
|
||||||
(showConfirmationKeyboardDelete &&
|
(showConfirmationKeyboardDelete &&
|
||||||
historyId === keyboardItemIdDelete &&
|
historyId === keyboardItemIdDelete &&
|
||||||
historyId === keyboardSelectedItemId.value) ||
|
historyId === keyboardSelectedItemId.value) ||
|
||||||
// Mouse delete confirmation - only when keyboard delete is NOT active
|
// Mouse delete confirmation - only when keyboard delete is NOT active
|
||||||
(showConfirmation && !showConfirmationKeyboardDelete && selectedHistoryItems.includes(historyId)) ||
|
(showConfirmation &&
|
||||||
|
!showConfirmationKeyboardDelete &&
|
||||||
|
selectedHistoryItems.includes(historyId)) ||
|
||||||
// Single item delete confirmation
|
// Single item delete confirmation
|
||||||
historyId === showHistoryDeleteConfirmationId.value ||
|
historyId === showHistoryDeleteConfirmationId.value ||
|
||||||
// Hovering delete confirmation - only when keyboard delete is NOT active
|
// Hovering delete confirmation - only when keyboard delete is NOT active
|
||||||
(showConfirmation && !showConfirmationKeyboardDelete && historyId === hoveringHistoryIdDelete) ||
|
(showConfirmation &&
|
||||||
|
!showConfirmationKeyboardDelete &&
|
||||||
|
historyId === hoveringHistoryIdDelete) ||
|
||||||
// Drag over trash
|
// Drag over trash
|
||||||
historyId === dragOverTrashId ||
|
historyId === dragOverTrashId ||
|
||||||
(Boolean(dragOverTrashId) &&
|
(Boolean(dragOverTrashId) &&
|
||||||
@ -2513,6 +2584,9 @@ export default function ClipboardHistoryPage() {
|
|||||||
historyPreviewLineLimit
|
historyPreviewLineLimit
|
||||||
}
|
}
|
||||||
index={index}
|
index={index}
|
||||||
|
setKeyboardHistorySelectedItemId={
|
||||||
|
setKeyboardHistorySelectedItemId
|
||||||
|
}
|
||||||
style={style}
|
style={style}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user