Merge pull request #259 from PasteBar/feat/history-preview-limit

History item preview max lines user setting
This commit is contained in:
Sergey 2025-06-20 23:29:03 -04:00 committed by GitHub
commit c00ff2b33f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
23 changed files with 334 additions and 170 deletions

View File

@ -0,0 +1,5 @@
---
'pastebar-app-ui': patch
---
Added: history item preview max lines user setting

View File

@ -129,6 +129,7 @@ function App() {
isCustomDbPathValid: null, isCustomDbPathValid: null,
customDbPathError: null, customDbPathError: null,
dbRelocationInProgress: false, dbRelocationInProgress: false,
historyPreviewLineLimit: settings.historyPreviewLineLimit?.valueInt ?? null,
appLastUpdateVersion: settings.appLastUpdateVersion?.valueText, appLastUpdateVersion: settings.appLastUpdateVersion?.valueText,
appLastUpdateDate: settings.appLastUpdateDate?.valueText, appLastUpdateDate: settings.appLastUpdateDate?.valueText,
isHideMacOSDockIcon: settings.isHideMacOSDockIcon?.valueBool, isHideMacOSDockIcon: settings.isHideMacOSDockIcon?.valueBool,

View File

@ -49,6 +49,7 @@ function QuickPasteApp() {
settingsStore.initSettings({ settingsStore.initSettings({
appDataDir: '', appDataDir: '',
isSingleClickToCopyPaste: settings.isSingleClickToCopyPaste?.valueBool, isSingleClickToCopyPaste: settings.isSingleClickToCopyPaste?.valueBool,
historyPreviewLineLimit: settings.historyPreviewLineLimit?.valueInt ?? null,
appLastUpdateVersion: settings.appLastUpdateVersion?.valueText, appLastUpdateVersion: settings.appLastUpdateVersion?.valueText,
appLastUpdateDate: settings.appLastUpdateDate?.valueText, appLastUpdateDate: settings.appLastUpdateDate?.valueText,
isHideMacOSDockIcon: settings.isHideMacOSDockIcon?.valueBool, isHideMacOSDockIcon: settings.isHideMacOSDockIcon?.valueBool,

View File

@ -181,7 +181,7 @@ export const CodeViewer: FC<CodeViewerProps> = ({
return ( return (
<Box className="relative"> <Box className="relative">
<OverlayScrollbarsComponent <OverlayScrollbarsComponent
className={`${isShowMore ? 'code-scroll-x pb-2' : ''}`} className={`${isShowMore ? 'code-scroll-x' : ''}`}
options={{ options={{
overflow: { overflow: {
x: !isShowMore ? 'hidden' : 'scroll', x: !isShowMore ? 'hidden' : 'scroll',

View File

@ -64,3 +64,6 @@ Keep Pinned Items: Angehängte Elemente beibehalten
Keep Starred Items: Mit Stern markierte Elemente beibehalten Keep Starred Items: Mit Stern markierte Elemente beibehalten
Preserve pinned items when clearing history: Angehängte Elemente beim Löschen des Verlaufs beibehalten Preserve pinned items when clearing history: Angehängte Elemente beim Löschen des Verlaufs beibehalten
Preserve starred items when clearing history: Mit Stern markierte Elemente beim Löschen des Verlaufs beibehalten Preserve starred items when clearing history: Mit Stern markierte Elemente beim Löschen des Verlaufs beibehalten
History Item Preview Max Lines: Maximale Vorschauzeilenanzahl für Verlaufselemente
Set the maximum number of lines to display in the preview of a history item: Maximale Anzahl der Zeilen für die Vorschau eines Verlaufselements festlegen
Preview Max Lines: Vorschauzeilen

View File

@ -1,38 +1,53 @@
App restart required: Restart required App restart required: Restart required
Application Starts with Main Window Hidden: Application Starts with Main Window Hidden Application Starts with Main Window Hidden: Application Starts with Main Window Hidden
Auto-close window after action: Auto-close window after action
Boards, saved clips and menu items panel visible: Boards, saved clips and menu items panel visible Boards, saved clips and menu items panel visible: Boards, saved clips and menu items panel visible
Both clipboard history and saved clips panels visible: Both clipboard history and saved clips panels visible Both clipboard history and saved clips panels visible: Both clipboard history and saved clips panels visible
Change: Change Change: Change
Click Set/Change button to start recording: Click Set/Change button to start recording
Clipboard history panel visible: Clipboard history panel visible Clipboard history panel visible: Clipboard history panel visible
Configure the behavior of the Quick Paste window when selecting items: Configure the behavior of the Quick Paste window when selecting items
Configure which items to preserve when clearing clipboard history (both manual and auto-clear operations).: Configure which items to preserve when clearing clipboard history (both manual and auto-clear operations).
Control which panels are visible in the main window: Control which panels are visible in the main window Control which panels are visible in the main window: Control which panels are visible in the main window
Copy items only (no auto-paste): Copy items only (no auto-paste)
Copy only from menu items: Copy only from menu items Copy only from menu items: Copy only from menu items
Default Note Icon Type: Default Note Icon Type Default Note Icon Type: Default Note Icon Type
Display navbar items only when the mouse hovers over the navigation bar to minimize visible UI elements: Display navbar items only when the mouse hovers over the navigation bar to minimize visible UI elements Display navbar items only when the mouse hovers over the navigation bar to minimize visible UI elements: Display navbar items only when the mouse hovers over the navigation bar to minimize visible UI elements
Display persistent icons on clips that have notes to improve visual organization and make notes easier to discover.: Display persistent icons on clips that have notes to improve visual organization and make notes easier to discover. Display persistent icons on clips that have notes to improve visual organization and make notes easier to discover.: Display persistent icons on clips that have notes to improve visual organization and make notes easier to discover.
Enable simplified, less boxy layout for a cleaner and more streamlined interface design: Enable simplified, less boxy layout for a cleaner and more streamlined interface design Enable simplified, less boxy layout for a cleaner and more streamlined interface design: Enable simplified, less boxy layout for a cleaner and more streamlined interface design
Enable single-click to copy/paste clipboard history items and saved clips instead of requiring double-click.: Enable single-click to copy/paste clipboard history items and saved clips instead of requiring double-click.
Global System OS Hotkeys: Global System OS Hotkeys Global System OS Hotkeys: Global System OS Hotkeys
Hide Collections Navbar: Hide Collections Navbar Hide Collections Navbar: Hide Collections Navbar
Hide collections menu dropdown on the navigation bar: Hide collections menu dropdown on the navigation bar Hide collections menu dropdown on the navigation bar: Hide collections menu dropdown on the navigation bar
Hide collections menu on the navbar: Hide collections menu on the navbar Hide collections menu on the navbar: Hide collections menu on the navbar
Hide the App Dock Icon: Hide the App Dock Icon Hide the App Dock Icon: Hide the App Dock Icon
History Item Preview Max Lines: History Item Preview Max Lines
'How to set hotkeys:': 'How to set hotkeys:'
Keep Items on Clear: Keep Items on Clear
Keep Pinned Items: Keep Pinned Items
Keep Starred Items: Keep Starred Items
? Keep the main application window hidden when the app restarts. You can reopen it using the menu bar or taskbar menu, or using global hotkeys. ? Keep the main application window hidden when the app restarts. You can reopen it using the menu bar or taskbar menu, or using global hotkeys.
: Keep the main application window hidden when the app restarts. You can reopen it using the menu bar or taskbar menu, or using global hotkeys. : Keep the main application window hidden when the app restarts. You can reopen it using the menu bar or taskbar menu, or using global hotkeys.
No keys set: No keys set No keys set: No keys set
'Note: At least one panel must remain visible in main window.': 'Note: At least one panel must remain visible in main window.' 'Note: At least one panel must remain visible in main window.': 'Note: At least one panel must remain visible in main window.'
Panel Visibility: Panel Visibility Panel Visibility: Panel Visibility
PasteBar Quick Paste: PasteBar Quick Paste PasteBar Quick Paste: PasteBar Quick Paste
Preserve pinned items when clearing history: Preserve pinned items when clearing history
Preserve starred items when clearing history: Preserve starred items when clearing history
Press Backspace/Delete to clear the hotkey: Press Backspace/Delete to clear the hotkey
Press Enter to confirm or Escape to cancel: Press Enter to confirm or Escape to cancel
Press keys: Press keys Press keys: Press keys
Press your desired key combination (e.g., Ctrl+Shift+V): Press your desired key combination (e.g., Ctrl+Shift+V)
Press your key combination...: Press your key combination...
Preview Max Lines: Preview Max Lines
Quick Paste Window: Quick Paste Window
Quick Paste Window Options: Quick Paste Window Options
Recording...: Recording...
? Remove PasteBar app icon from the macOS Dock while keeping the app running in the background. The app remains accessible via the menu bar icon. Requires an app restart to take effect. ? Remove PasteBar app icon from the macOS Dock while keeping the app running in the background. The app remains accessible via the menu bar icon. Requires an app restart to take effect.
: Remove PasteBar app icon from the macOS Dock while keeping the app running in the background. The app remains accessible via the menu bar icon. Requires an app restart to take effect. : Remove PasteBar app icon from the macOS Dock while keeping the app running in the background. The app remains accessible via the menu bar icon. Requires an app restart to take effect.
Set: Set Set: Set
Set system OS hotkeys to show/hide the main app window and quick paste window. Supports up to 3-key combinations.: Set system OS hotkeys to show/hide the main app window and quick paste window. Supports up to 3-key combinations. Set system OS hotkeys to show/hide the main app window and quick paste window. Supports up to 3-key combinations.: Set system OS hotkeys to show/hide the main app window and quick paste window. Supports up to 3-key combinations.
'How to set hotkeys:': 'How to set hotkeys:' Set the maximum number of lines to display in the preview of a history item: Set the maximum number of lines to display in the preview of a history item
Click Set/Change button to start recording: Click Set/Change button to start recording
Press your desired key combination (e.g., Ctrl+Shift+V): Press your desired key combination (e.g., Ctrl+Shift+V)
Press Enter to confirm or Escape to cancel: Press Enter to confirm or Escape to cancel
Press Backspace/Delete to clear the hotkey: Press Backspace/Delete to clear the hotkey
Press your key combination...: Press your key combination...
Recording...: Recording...
Show Boards and Clips Panel Only: Show Boards and Clips Panel Only Show Boards and Clips Panel Only: Show Boards and Clips Panel Only
Show Both Panels: Show Both Panels Show Both Panels: Show Both Panels
Show History Panel Only: Show History Panel Only Show History Panel Only: Show History Panel Only
@ -44,15 +59,8 @@ Show navbar elements on hover only: Show navbar elements on hover only
Show/Hide Main App Window: Show/Hide Main App Window Show/Hide Main App Window: Show/Hide Main App Window
Show/Hide Quick Paste Window: Show/Hide Quick Paste Window Show/Hide Quick Paste Window: Show/Hide Quick Paste Window
Simplified Panel Layout: Simplified Panel Layout Simplified Panel Layout: Simplified Panel Layout
When enabled, the Quick Paste window will automatically close after copying or pasting an item.: When enabled, the Quick Paste window will automatically close after copying or pasting an item.
Enable single-click to copy/paste clipboard history items and saved clips instead of requiring double-click.: Enable single-click to copy/paste clipboard history items and saved clips instead of requiring double-click.
Single Click Copy/Paste action: Single Click Copy/Paste action
Single Click Copy/Paste: Single Click Copy/Paste Single Click Copy/Paste: Single Click Copy/Paste
Quick Paste Window: Quick Paste Window Single Click Copy/Paste action: Single Click Copy/Paste action
Quick Paste Window Options: Quick Paste Window Options
Configure the behavior of the Quick Paste window when selecting items: Configure the behavior of the Quick Paste window when selecting items
Copy items only (no auto-paste): Copy items only (no auto-paste)
Auto-close window after action: Auto-close window after action
This sets the default icon type for new clips with notes. You can customize individual clips via the context menu.: This sets the default icon type for new clips with notes. You can customize individual clips via the context menu. This sets the default icon type for new clips with notes. You can customize individual clips via the context menu.: This sets the default icon type for new clips with notes. You can customize individual clips via the context menu.
? When enabled, clicking menu items will only copy content to clipboard instead of auto-pasting. This gives you more control over when and where content is pasted. ? When enabled, clicking menu items will only copy content to clipboard instead of auto-pasting. This gives you more control over when and where content is pasted.
: When enabled, clicking menu items will only copy content to clipboard instead of auto-pasting. This gives you more control over when and where content is pasted. : When enabled, clicking menu items will only copy content to clipboard instead of auto-pasting. This gives you more control over when and where content is pasted.
@ -60,9 +68,4 @@ This sets the default icon type for new clips with notes. You can customize indi
: When enabled, clicking or pressing Enter on items in Quick Paste window will only copy them to clipboard without automatically pasting. : When enabled, clicking or pressing Enter on items in Quick Paste window will only copy them to clipboard without automatically pasting.
? When enabled, single click will copy/paste items in Quick Paste window. If global single click is also enabled, both settings work together. ? When enabled, single click will copy/paste items in Quick Paste window. If global single click is also enabled, both settings work together.
: When enabled, single click will copy/paste items in Quick Paste window. If global single click is also enabled, both settings work together. : When enabled, single click will copy/paste items in Quick Paste window. If global single click is also enabled, both settings work together.
Configure which items to preserve when clearing clipboard history (both manual and auto-clear operations).: Configure which items to preserve when clearing clipboard history (both manual and auto-clear operations). When enabled, the Quick Paste window will automatically close after copying or pasting an item.: When enabled, the Quick Paste window will automatically close after copying or pasting an item.
Keep Items on Clear: Keep Items on Clear
Keep Pinned Items: Keep Pinned Items
Keep Starred Items: Keep Starred Items
Preserve pinned items when clearing history: Preserve pinned items when clearing history
Preserve starred items when clearing history: Preserve starred items when clearing history

View File

@ -64,3 +64,6 @@ Keep Pinned Items: Conservar elementos fijados
Keep Starred Items: Conservar elementos destacados Keep Starred Items: Conservar elementos destacados
Preserve pinned items when clearing history: Conservar elementos fijados al borrar el historial Preserve pinned items when clearing history: Conservar elementos fijados al borrar el historial
Preserve starred items when clearing history: Conservar elementos destacados al borrar el historial Preserve starred items when clearing history: Conservar elementos destacados al borrar el historial
History Item Preview Max Lines: Límite máximo de líneas de vista previa de elementos del historial
Set the maximum number of lines to display in the preview of a history item: Establecer el número máximo de líneas para mostrar en la vista previa de un elemento del historial
Preview Max Lines: Líneas de vista previa

View File

@ -64,3 +64,6 @@ Keep Pinned Items: Conserver les éléments épinglés
Keep Starred Items: Conserver les éléments favoris Keep Starred Items: Conserver les éléments favoris
Preserve pinned items when clearing history: Conserver les éléments épinglés lors de l'effacement de l'historique Preserve pinned items when clearing history: Conserver les éléments épinglés lors de l'effacement de l'historique
Preserve starred items when clearing history: Conserver les éléments favoris lors de l'effacement de l'historique Preserve starred items when clearing history: Conserver les éléments favoris lors de l'effacement de l'historique
History Item Preview Max Lines: Limite maximale de lignes d'aperçu des éléments de l'historique
Set the maximum number of lines to display in the preview of a history item: Définir le nombre maximal de lignes à afficher dans l'aperçu d'un élément de l'historique
Preview Max Lines: Lignes d'aperçu

View File

@ -64,3 +64,6 @@ Keep Pinned Items: Conserva elementi fissati
Keep Starred Items: Conserva elementi preferiti Keep Starred Items: Conserva elementi preferiti
Preserve pinned items when clearing history: Conserva elementi fissati durante la cancellazione della cronologia Preserve pinned items when clearing history: Conserva elementi fissati durante la cancellazione della cronologia
Preserve starred items when clearing history: Conserva elementi preferiti durante la cancellazione della cronologia Preserve starred items when clearing history: Conserva elementi preferiti durante la cancellazione della cronologia
History Item Preview Max Lines: Limite massimo di righe di anteprima degli elementi della cronologia
Set the maximum number of lines to display in the preview of a history item: Imposta il numero massimo di righe da visualizzare nell'anteprima di un elemento della cronologia
Preview Max Lines: Righe di anteprima

View File

@ -64,3 +64,6 @@ Keep Pinned Items: Сохранять закрепленные элементы
Keep Starred Items: Сохранять избранные элементы Keep Starred Items: Сохранять избранные элементы
Preserve pinned items when clearing history: Сохранять закрепленные элементы при очистке истории Preserve pinned items when clearing history: Сохранять закрепленные элементы при очистке истории
Preserve starred items when clearing history: Сохранять избранные элементы при очистке истории Preserve starred items when clearing history: Сохранять избранные элементы при очистке истории
History Item Preview Max Lines: Количество строк предварительного просмотра элементов истории
Set the maximum number of lines to display in the preview of a history item: Установить максимальное количество строк для отображения в предварительном просмотре элемента истории
Preview Max Lines: Максимум строк просмотра

View File

@ -64,3 +64,6 @@ Keep Pinned Items: Sabitlenmiş öğeleri koru
Keep Starred Items: Favorilenmiş öğeleri koru Keep Starred Items: Favorilenmiş öğeleri koru
Preserve pinned items when clearing history: Geçmişi temizlerken sabitlenmiş öğeleri koru Preserve pinned items when clearing history: Geçmişi temizlerken sabitlenmiş öğeleri koru
Preserve starred items when clearing history: Geçmişi temizlerken favorilenmiş öğeleri koru Preserve starred items when clearing history: Geçmişi temizlerken favorilenmiş öğeleri koru
History Item Preview Max Lines: Geçmiş öğesi önizleme maksimum satır sayısı
Set the maximum number of lines to display in the preview of a history item: Bir geçmiş öğesinin önizlemesinde gösterilecek maksimum satır sayısını ayarla
Preview Max Lines: Önizleme Satırları

View File

@ -64,3 +64,6 @@ Keep Pinned Items: Зберігати закріплені елементи
Keep Starred Items: Зберігати обрані елементи Keep Starred Items: Зберігати обрані елементи
Preserve pinned items when clearing history: Зберігати закріплені елементи під час очищення історії Preserve pinned items when clearing history: Зберігати закріплені елементи під час очищення історії
Preserve starred items when clearing history: Зберігати обрані елементи під час очищення історії Preserve starred items when clearing history: Зберігати обрані елементи під час очищення історії
History Item Preview Max Lines: Рядки перегляду історії
Set the maximum number of lines to display in the preview of a history item: Встановити максимальну кількість рядків для відображення в попередньому перегляді елемента історії
Preview Max Lines: Рядки перегляду

View File

@ -64,3 +64,6 @@ Keep Pinned Items: 保留已固定项目
Keep Starred Items: 保留已星标项目 Keep Starred Items: 保留已星标项目
Preserve pinned items when clearing history: 清除历史记录时保留已固定项目 Preserve pinned items when clearing history: 清除历史记录时保留已固定项目
Preserve starred items when clearing history: 清除历史记录时保留已星标项目 Preserve starred items when clearing history: 清除历史记录时保留已星标项目
History Item Preview Max Lines: 历史项目预览最大行数
Set the maximum number of lines to display in the preview of a history item: 设置历史项目预览中显示的最大行数
Preview Max Lines: 预览行数

View File

@ -189,7 +189,7 @@ export function ClipboardHistoryLargeViewComponent({
</Box> </Box>
) : clipboard.detectedLanguage && clipboard.valuePreview ? ( ) : clipboard.detectedLanguage && clipboard.valuePreview ? (
<Box <Box
className="text-ellipsis self-start text-sm w-full p-1.5 animate-in fade-in" className="text-ellipsis self-start text-sm w-full animate-in fade-in"
key={clipboard.historyId} key={clipboard.historyId}
> >
<Highlight <Highlight
@ -215,34 +215,41 @@ export function ClipboardHistoryLargeViewComponent({
}} }}
> >
<code className={`${className}`} style={style}> <code className={`${className}`} style={style}>
{tokens.map((line, i) => { {tokens
return ( .filter((line, i) => {
<div if (i === tokens.length - 1) {
key={i} return line.some(token => token.content.trim() !== '')
{...getLineProps({ line })} }
className={`${ return true
isWrapText })
? 'whitespace-pre-wrap' .map((line, i) => {
: 'whitespace-pre' return (
} overflow-hidden text-ellipsis`} <div
> key={i}
{line.map((token, key) => ( {...getLineProps({ line })}
<span className={`${
key={key} isWrapText
{...getTokenProps({ token })} ? 'whitespace-pre-wrap'
className="select-text" : 'whitespace-pre'
> } overflow-hidden text-ellipsis`}
{!searchTerm >
? token.content {line.map((token, key) => (
: highlightMatchedText( <span
token.content, key={key}
searchTerm {...getTokenProps({ token })}
)} className="select-text"
</span> >
))} {!searchTerm
</div> ? token.content
) : highlightMatchedText(
})} token.content,
searchTerm
)}
</span>
))}
</div>
)
})}
</code> </code>
</OverlayScrollbarsComponent> </OverlayScrollbarsComponent>
) )
@ -291,9 +298,6 @@ export function ClipboardHistoryLargeViewComponent({
{searchTerm {searchTerm
? highlightMatchedText(textValue, searchTerm) ? highlightMatchedText(textValue, searchTerm)
: hyperlinkText(textValue, clipboard.arrLinks)} : hyperlinkText(textValue, clipboard.arrLinks)}
{clipboard.valueMorePreviewChars && (
<Box className="select-none"> {'\u00A0'} </Box>
)}
</code> </code>
</Box> </Box>
)} )}

View File

@ -13,6 +13,7 @@ import WrapIcon from '~/assets/icons/wrap'
import { MINUTE_IN_MS } from '~/constants' import { MINUTE_IN_MS } from '~/constants'
import { isEmailNotUrl } from '~/libs/utils' import { isEmailNotUrl } from '~/libs/utils'
import { formatLocale as format } from '~/locales/date-locales' import { formatLocale as format } from '~/locales/date-locales'
import { getValuePreview } from '~/pages/components/Dashboard/components/utils'
import { hoveringHistoryRowId, isKeyAltPressed, isKeyCtrlPressed } from '~/store' import { hoveringHistoryRowId, isKeyAltPressed, isKeyCtrlPressed } from '~/store'
import { Check, Dot, Star } from 'lucide-react' import { Check, Dot, Star } from 'lucide-react'
import { Highlight, themes } from 'prism-react-renderer' import { Highlight, themes } from 'prism-react-renderer'
@ -103,6 +104,7 @@ interface ClipboardHistoryQuickPasteRowProps {
setHistoryFilters?: Dispatch<SetStateAction<string[]>> setHistoryFilters?: Dispatch<SetStateAction<string[]>>
setAppFilters?: Dispatch<SetStateAction<string[]>> setAppFilters?: Dispatch<SetStateAction<string[]>>
isSingleClickToCopyPaste?: boolean isSingleClickToCopyPaste?: boolean
historyPreviewLineLimit?: number | null
} }
// eslint-disable-next-line sonarjs/cognitive-complexity // eslint-disable-next-line sonarjs/cognitive-complexity
@ -116,8 +118,6 @@ export function ClipboardHistoryQuickPasteRowComponent({
isPinnedTop = false, isPinnedTop = false,
isPinnedTopFirst = false, isPinnedTopFirst = false,
isWindows, isWindows,
isDisabledPinnedMoveUp = false,
isDisabledPinnedMoveDown = false,
isExpanded = false, isExpanded = false,
isSelected = false, isSelected = false,
isWrapText = false, isWrapText = false,
@ -155,14 +155,13 @@ export function ClipboardHistoryQuickPasteRowComponent({
isDragPreview = false, isDragPreview = false,
setRowHeight = () => {}, setRowHeight = () => {},
isSingleClickToCopyPaste = false, isSingleClickToCopyPaste = false,
historyPreviewLineLimit,
}: ClipboardHistoryQuickPasteRowProps) { }: ClipboardHistoryQuickPasteRowProps) {
const { t } = useTranslation() const { t } = useTranslation()
const rowRef = useRef<HTMLDivElement>(null) const rowRef = useRef<HTMLDivElement>(null)
const rowKeyboardRef = useRef<HTMLDivElement>(null) const rowKeyboardRef = useRef<HTMLDivElement>(null)
const isCopiedOrPasted = isCopied || isPasted || isSaved const isCopiedOrPasted = isCopied || isPasted || isSaved
console.log('isSingleClickToCopyPaste', isSingleClickToCopyPaste)
const contentElementRendered = useSignal<boolean>(false) const contentElementRendered = useSignal<boolean>(false)
const contextMenuOpen = useSignal<boolean>(false) const contextMenuOpen = useSignal<boolean>(false)
@ -259,6 +258,37 @@ export function ClipboardHistoryQuickPasteRowComponent({
const isNowItem = index === 0 && clipboard.updatedAt > Date.now() - MINUTE_IN_MS const isNowItem = index === 0 && clipboard.updatedAt > Date.now() - MINUTE_IN_MS
const isMp3 = clipboard?.isLink && clipboard?.value?.endsWith('.mp3') const isMp3 = clipboard?.isLink && clipboard?.value?.endsWith('.mp3')
const { valuePreview, valueMorePreviewLines, valueMorePreviewChars } = useMemo(() => {
if (historyPreviewLineLimit && historyPreviewLineLimit > 0 && clipboard?.value) {
const result = getValuePreview(
clipboard.value,
clipboard.isImageData || false,
isExpanded,
historyPreviewLineLimit,
true
)
return {
valuePreview: result.valuePreview,
valueMorePreviewLines: result.morePreviewLines,
valueMorePreviewChars: result.morePreviewChars,
}
}
return {
valuePreview: clipboard?.valuePreview || '',
valueMorePreviewLines: clipboard?.valueMorePreviewLines || null,
valueMorePreviewChars: clipboard?.valueMorePreviewChars || null,
}
}, [
historyPreviewLineLimit,
clipboard?.value,
clipboard?.isImageData,
isExpanded,
clipboard?.valuePreview,
clipboard?.valueMorePreviewLines,
clipboard?.valueMorePreviewChars,
])
useEffect(() => { useEffect(() => {
if ( if (
!hasLinkCard && !hasLinkCard &&
@ -476,7 +506,7 @@ export function ClipboardHistoryQuickPasteRowComponent({
{searchTerm ? ( {searchTerm ? (
highlightWithPreviewMatchedText(clipboard.value, searchTerm) highlightWithPreviewMatchedText(clipboard.value, searchTerm)
) : ( ) : (
<span>{clipboard.valuePreview}</span> <span>{valuePreview}</span>
)} )}
</code> </code>
</Box> </Box>
@ -526,7 +556,7 @@ export function ClipboardHistoryQuickPasteRowComponent({
className="max-w-full max-h-56 min-h-10 rounded-md shadow-sm border border-slate-100 dark:border-slate-700" className="max-w-full max-h-56 min-h-10 rounded-md shadow-sm border border-slate-100 dark:border-slate-700"
/> />
</Box> </Box>
) : clipboard.detectedLanguage && clipboard.valuePreview ? ( ) : clipboard.detectedLanguage && valuePreview ? (
<Box <Box
ref={ref => { ref={ref => {
if (ref) { if (ref) {
@ -537,7 +567,7 @@ export function ClipboardHistoryQuickPasteRowComponent({
> >
<Highlight <Highlight
theme={isDark ? themes.vsDark : themes.github} theme={isDark ? themes.vsDark : themes.github}
code={isExpanded ? textValue : clipboard.valuePreview.trim()} code={isExpanded ? textValue : valuePreview.trim()}
language={clipboard.detectedLanguage} language={clipboard.detectedLanguage}
> >
{({ className, style, tokens, getLineProps, getTokenProps }) => { {({ className, style, tokens, getLineProps, getTokenProps }) => {
@ -546,7 +576,7 @@ export function ClipboardHistoryQuickPasteRowComponent({
{tokens.map((line, i) => { {tokens.map((line, i) => {
const isLastLine = const isLastLine =
i === tokens.length - 1 && i === tokens.length - 1 &&
clipboard.valueMorePreviewLines && valueMorePreviewLines &&
!isExpanded !isExpanded
return ( return (
<div <div
@ -575,9 +605,6 @@ export function ClipboardHistoryQuickPasteRowComponent({
) )
}} }}
</Highlight> </Highlight>
{clipboard.valueMorePreviewLines && (
<Box className="select-none"> {'\u00A0'} </Box>
)}
</Box> </Box>
) : ( ) : (
<Box <Box
@ -610,28 +637,19 @@ export function ClipboardHistoryQuickPasteRowComponent({
{searchTerm {searchTerm
? highlightMatchedText(textValue, searchTerm) ? highlightMatchedText(textValue, searchTerm)
: hyperlinkText(textValue, clipboard.arrLinks)} : hyperlinkText(textValue, clipboard.arrLinks)}
{clipboard.valueMorePreviewChars && (
<Box className="select-none"> {'\u00A0'} </Box>
)}
</code> </code>
) : ( ) : (
<code className="justify-start cursor-pointer"> <code className="justify-start cursor-pointer whitespace-pre">
{searchTerm {searchTerm
? highlightWithPreviewMatchedText(textValue ?? '', searchTerm) ? highlightWithPreviewMatchedText(textValue ?? '', searchTerm)
: hyperlinkTextWithPreview({ : hyperlinkTextWithPreview({
previewLinkCard: !hasLinkCard && isLinkCardPreviewEnabled, previewLinkCard: !hasLinkCard && isLinkCardPreviewEnabled,
isPreviewError: hasClipboardHistoryURLErrors, isPreviewError: hasClipboardHistoryURLErrors,
value: clipboard.valuePreview ?? '', value: valuePreview ?? '',
links: clipboard.arrLinks, links: clipboard.arrLinks,
itemId: null, itemId: null,
historyId: clipboard.historyId, historyId: clipboard.historyId,
})} })}
{clipboard.valueMorePreviewChars && (
<>
<span className="select-none">...</span>
<Box className="select-none"> {'\u00A0'} </Box>
</>
)}
{isMp3 && ( {isMp3 && (
<PlayButton <PlayButton
src={textValue} src={textValue}
@ -647,7 +665,7 @@ export function ClipboardHistoryQuickPasteRowComponent({
)} )}
</Box> </Box>
)} )}
{(clipboard.valueMorePreviewLines || clipboard.valueMorePreviewChars) && ( {(valueMorePreviewLines || valueMorePreviewChars) && (
<Box <Box
className={`absolute left-1 bottom-1 flex flex-row items-center rounded mb-[2px] pl-0.5 ${bgToolsPanel}`} className={`absolute left-1 bottom-1 flex flex-row items-center rounded mb-[2px] pl-0.5 ${bgToolsPanel}`}
> >
@ -666,15 +684,13 @@ export function ClipboardHistoryQuickPasteRowComponent({
sideOffset={10} sideOffset={10}
> >
{!isExpanded ? ( {!isExpanded ? (
clipboard?.valueMorePreviewChars ? ( valueMorePreviewChars ? (
<> <>
+{clipboard.valueMorePreviewChars}{' '} +{valueMorePreviewChars} {t('chars', { ns: 'common' })}
{t('chars', { ns: 'common' })}
</> </>
) : ( ) : (
<> <>
+{clipboard.valueMorePreviewLines}{' '} +{valueMorePreviewLines} {t('lines', { ns: 'common' })}
{t('lines', { ns: 'common' })}
</> </>
) )
) : ( ) : (

View File

@ -13,6 +13,7 @@ import WrapIcon from '~/assets/icons/wrap'
import { MINUTE_IN_MS } from '~/constants' import { MINUTE_IN_MS } from '~/constants'
import { isEmailNotUrl } from '~/libs/utils' import { isEmailNotUrl } from '~/libs/utils'
import { formatLocale as format } from '~/locales/date-locales' import { formatLocale as format } from '~/locales/date-locales'
import { getValuePreview } from '~/pages/components/Dashboard/components/utils'
import { import {
hoveringHistoryRowId, hoveringHistoryRowId,
isKeyAltPressed, isKeyAltPressed,
@ -122,6 +123,7 @@ interface ClipboardHistoryRowProps {
setHistoryFilters?: Dispatch<SetStateAction<string[]>> setHistoryFilters?: Dispatch<SetStateAction<string[]>>
setAppFilters?: Dispatch<SetStateAction<string[]>> setAppFilters?: Dispatch<SetStateAction<string[]>>
isSingleClickToCopyPaste?: boolean isSingleClickToCopyPaste?: boolean
historyPreviewLineLimit?: number
} }
// eslint-disable-next-line sonarjs/cognitive-complexity // eslint-disable-next-line sonarjs/cognitive-complexity
@ -180,6 +182,7 @@ export function ClipboardHistoryRowComponent({
setHistoryFilters = () => {}, setHistoryFilters = () => {},
setAppFilters = () => {}, setAppFilters = () => {},
isSingleClickToCopyPaste = false, isSingleClickToCopyPaste = false,
historyPreviewLineLimit,
}: ClipboardHistoryRowProps) { }: ClipboardHistoryRowProps) {
const { t } = useTranslation() const { t } = useTranslation()
const rowRef = useRef<HTMLDivElement>(null) const rowRef = useRef<HTMLDivElement>(null)
@ -224,6 +227,7 @@ export function ClipboardHistoryRowComponent({
// eslint-disable-next-line // eslint-disable-next-line
}, [ }, [
contentElementRendered.value, contentElementRendered.value,
historyPreviewLineLimit,
rowRef.current?.clientHeight, rowRef.current?.clientHeight,
setRowHeight, setRowHeight,
timeAgo, timeAgo,
@ -285,6 +289,36 @@ export function ClipboardHistoryRowComponent({
const isNowItem = index === 0 && clipboard.updatedAt > Date.now() - MINUTE_IN_MS const isNowItem = index === 0 && clipboard.updatedAt > Date.now() - MINUTE_IN_MS
const isMp3 = clipboard?.isLink && clipboard?.value?.endsWith('.mp3') const isMp3 = clipboard?.isLink && clipboard?.value?.endsWith('.mp3')
const { valuePreview, valueMorePreviewLines, valueMorePreviewChars } = useMemo(() => {
if (historyPreviewLineLimit && historyPreviewLineLimit > 0 && clipboard?.value) {
const result = getValuePreview(
clipboard.value,
clipboard.isImageData || false,
isExpanded,
historyPreviewLineLimit,
true
)
return {
valuePreview: result.valuePreview,
valueMorePreviewLines: result.morePreviewLines,
valueMorePreviewChars: result.morePreviewChars,
}
}
return {
valuePreview: clipboard?.valuePreview || '',
valueMorePreviewLines: clipboard?.valueMorePreviewLines || null,
valueMorePreviewChars: clipboard?.valueMorePreviewChars || null,
}
}, [
historyPreviewLineLimit,
clipboard?.value,
clipboard?.isImageData,
isExpanded,
clipboard?.valuePreview,
clipboard?.valueMorePreviewLines,
clipboard?.valueMorePreviewChars,
])
useEffect(() => { useEffect(() => {
if ( if (
!hasLinkCard && !hasLinkCard &&
@ -554,7 +588,7 @@ export function ClipboardHistoryRowComponent({
{searchTerm ? ( {searchTerm ? (
highlightWithPreviewMatchedText(clipboard.value, searchTerm) highlightWithPreviewMatchedText(clipboard.value, searchTerm)
) : ( ) : (
<span>{clipboard.valuePreview}</span> <span>{valuePreview}</span>
)} )}
</code> </code>
</Box> </Box>
@ -604,7 +638,7 @@ export function ClipboardHistoryRowComponent({
className="max-w-full max-h-56 min-h-10 rounded-md shadow-sm border border-slate-100 dark:border-slate-700" className="max-w-full max-h-56 min-h-10 rounded-md shadow-sm border border-slate-100 dark:border-slate-700"
/> />
</Box> </Box>
) : clipboard.detectedLanguage && clipboard.valuePreview ? ( ) : clipboard.detectedLanguage && valuePreview ? (
<Box <Box
ref={ref => { ref={ref => {
if (ref) { if (ref) {
@ -615,17 +649,13 @@ export function ClipboardHistoryRowComponent({
> >
<Highlight <Highlight
theme={isDark ? themes.vsDark : themes.github} theme={isDark ? themes.vsDark : themes.github}
code={isExpanded ? stringValue : clipboard.valuePreview} code={isExpanded ? stringValue : valuePreview}
language={clipboard.detectedLanguage} language={clipboard.detectedLanguage}
> >
{({ className, style, tokens, getLineProps, getTokenProps }) => { {({ className, style, tokens, getLineProps, getTokenProps }) => {
return ( return (
<code className={`${className}`} style={style}> <code className={`${className}`} style={style}>
{tokens.map((line, i) => { {tokens.map((line, i) => {
const isLastLine =
i === tokens.length - 1 &&
clipboard.valueMorePreviewLines &&
!isExpanded
return ( return (
<div <div
key={i} key={i}
@ -650,9 +680,6 @@ export function ClipboardHistoryRowComponent({
)} )}
</span> </span>
))} ))}
{isLastLine && (
<span className="select-none">...</span>
)}
</div> </div>
) )
})} })}
@ -660,9 +687,6 @@ export function ClipboardHistoryRowComponent({
) )
}} }}
</Highlight> </Highlight>
{clipboard.valueMorePreviewLines && (
<Box className="select-none"> {'\u00A0'} </Box>
)}
</Box> </Box>
) : ( ) : (
<Box <Box
@ -695,9 +719,6 @@ export function ClipboardHistoryRowComponent({
{searchTerm {searchTerm
? highlightMatchedText(stringValue, searchTerm) ? highlightMatchedText(stringValue, searchTerm)
: hyperlinkText(stringValue, clipboard.arrLinks)} : hyperlinkText(stringValue, clipboard.arrLinks)}
{clipboard.valueMorePreviewChars && (
<Box className="select-none"> {'\u00A0'} </Box>
)}
</code> </code>
) : ( ) : (
<code className="justify-start cursor-pointer whitespace-pre"> <code className="justify-start cursor-pointer whitespace-pre">
@ -709,17 +730,11 @@ export function ClipboardHistoryRowComponent({
: hyperlinkTextWithPreview({ : hyperlinkTextWithPreview({
previewLinkCard: !hasLinkCard && isLinkCardPreviewEnabled, previewLinkCard: !hasLinkCard && isLinkCardPreviewEnabled,
isPreviewError: hasClipboardHistoryURLErrors, isPreviewError: hasClipboardHistoryURLErrors,
value: clipboard.valuePreview ?? '', value: valuePreview ?? '',
links: clipboard.arrLinks, links: clipboard.arrLinks,
itemId: null, itemId: null,
historyId: clipboard.historyId, historyId: clipboard.historyId,
})} })}
{clipboard.valueMorePreviewChars && (
<>
<span className="select-none">...</span>
<Box className="select-none"> {'\u00A0'} </Box>
</>
)}
{isMp3 && ( {isMp3 && (
<PlayButton <PlayButton
src={stringValue} src={stringValue}
@ -735,68 +750,66 @@ export function ClipboardHistoryRowComponent({
)} )}
</Box> </Box>
)} )}
{(clipboard.valueMorePreviewLines || {(valueMorePreviewLines || valueMorePreviewChars) &&
clipboard.valueMorePreviewChars) && ( !isCopiedOrPasted && (
<Box
className={`absolute left-1 bottom-1 flex flex-row items-center rounded mb-[2px] pl-0.5 ${bgToolsPanel}`}
>
<Box <Box
className={`text-xs text-muted-foreground px-1 cursor-pointer`} className={`absolute left-1 bottom-1 flex flex-row items-center rounded mb-[2px] pl-0.5 ${bgToolsPanel}`}
onClick={() => {
setExpanded(clipboard.historyId, !isExpanded)
}}
> >
<ToolTip
text={!isExpanded ? t('Show all', { ns: 'common' }) : ''}
isCompact
isDisabled={isExpanded || isDragPreview}
delayDuration={2000}
side="bottom"
sideOffset={10}
>
{!isExpanded ? (
clipboard?.valueMorePreviewChars ? (
<>
+{clipboard.valueMorePreviewChars}{' '}
{t('chars', { ns: 'common' })}
</>
) : (
<>
+{clipboard.valueMorePreviewLines}{' '}
{t('lines', { ns: 'common' })}
</>
)
) : (
<>- {t('show less', { ns: 'common' })}</>
)}
</ToolTip>
</Box>
{isExpanded && (
<Box <Box
className={`text-xs text-muted-foreground px-1.5 cursor-pointer`} className={`text-xs text-muted-foreground px-1 cursor-pointer`}
onClick={() => setWrapText(clipboard.historyId, !isWrapText)} onClick={() => {
setExpanded(clipboard.historyId, !isExpanded)
}}
> >
<ToolTip <ToolTip
text={ text={!isExpanded ? t('Show all', { ns: 'common' }) : ''}
!isWrapText
? t('Lines Wrap', { ns: 'common' })
: t('No Wrap', { ns: 'common' })
}
delayDuration={2000}
isCompact isCompact
isDisabled={isExpanded || isDragPreview}
delayDuration={2000}
side="bottom" side="bottom"
sideOffset={10} sideOffset={10}
> >
{!isWrapText ? ( {!isExpanded ? (
<WrapIcon width={20} height={20} /> valueMorePreviewChars ? (
<>
+{valueMorePreviewChars} {t('chars', { ns: 'common' })}
</>
) : (
<>
+{valueMorePreviewLines} {t('lines', { ns: 'common' })}
</>
)
) : ( ) : (
<NoWrapIcon width={20} height={20} /> <>- {t('show less', { ns: 'common' })}</>
)} )}
</ToolTip> </ToolTip>
</Box> </Box>
)} {isExpanded && (
</Box> <Box
)} className={`text-xs text-muted-foreground px-1.5 cursor-pointer`}
onClick={() => setWrapText(clipboard.historyId, !isWrapText)}
>
<ToolTip
text={
!isWrapText
? t('Lines Wrap', { ns: 'common' })
: t('No Wrap', { ns: 'common' })
}
delayDuration={2000}
isCompact
side="bottom"
sideOffset={10}
>
{!isWrapText ? (
<WrapIcon width={20} height={20} />
) : (
<NoWrapIcon width={20} height={20} />
)}
</ToolTip>
</Box>
)}
</Box>
)}
{clipboard.isImage && !clipboard.isLink && ( {clipboard.isImage && !clipboard.isLink && (
<Box className="absolute left-1 bottom-1 flex flex-row gap-1 rounded items-center pb-0.5 pl-0.5 z-100"> <Box className="absolute left-1 bottom-1 flex flex-row gap-1 rounded items-center pb-0.5 pl-0.5 z-100">
<Box <Box

View File

@ -68,7 +68,7 @@ interface ClipboardHistoryRowContextMenuProps {
arrLinks: string[] arrLinks: string[]
isImage: boolean isImage: boolean
isText: boolean isText: boolean
copiedFromApp: string | null copiedFromApp?: string | null
isMasked: boolean isMasked: boolean
isImageData: boolean isImageData: boolean
isMp3: boolean | undefined isMp3: boolean | undefined

View File

@ -212,7 +212,9 @@ export function getValueMorePreviewLines(value: string) {
export function getValuePreview( export function getValuePreview(
value: string, value: string,
isImageData: boolean = false, isImageData: boolean = false,
isLargeView: boolean = false isLargeView: boolean = false,
historyPreviewLineLimit?: number | null,
isHistoryItem?: boolean | undefined
): { ): {
valuePreview: string valuePreview: string
morePreviewLines: number | null morePreviewLines: number | null
@ -248,7 +250,10 @@ export function getValuePreview(
} }
// For non-image data, proceed with line-based truncation // For non-image data, proceed with line-based truncation
const MAX_PREVIEW_LINES = 5 const MAX_PREVIEW_LINES =
historyPreviewLineLimit && isHistoryItem && historyPreviewLineLimit > 0
? historyPreviewLineLimit
: 5
const normalizedValue = value.replace(/\r\n/g, '\n') const normalizedValue = value.replace(/\r\n/g, '\n')
const allLines = normalizedValue.split('\n') const allLines = normalizedValue.split('\n')
@ -305,18 +310,6 @@ export function getValuePreview(
finalPreviewText = bbCode.closeTags(finalPreviewText) finalPreviewText = bbCode.closeTags(finalPreviewText)
} }
if (calculatedMorePreviewLines > 0) {
// Add ellipsis if lines were actually truncated.
// Avoid adding if bbCode.closeTags might have added its own form of ellipsis or if preview ends with one.
if (!finalPreviewText.trim().endsWith('...')) {
// Check if the last line of previewText is just "..." from a previous logic
const linesInPreview = finalPreviewText.split('\n')
if (linesInPreview[linesInPreview.length - 1] !== '...') {
finalPreviewText += '\n...'
}
}
}
return { return {
valuePreview: finalPreviewText, valuePreview: finalPreviewText,
morePreviewLines: calculatedMorePreviewLines > 0 ? calculatedMorePreviewLines : null, morePreviewLines: calculatedMorePreviewLines > 0 ? calculatedMorePreviewLines : null,

View File

@ -90,7 +90,7 @@ export function MenuCardViewBody({
const { t } = useTranslation() const { t } = useTranslation()
const isWrapText = useSignal(false) const isWrapText = useSignal(false)
const { valuePreview, morePreviewLines, morePreviewChars } = getValuePreview(value) const { valuePreview, morePreviewLines, morePreviewChars } = getValuePreview(value, false, false)
const textValue: string = value || '' const textValue: string = value || ''
const isBrokenImage = useSignal(false) const isBrokenImage = useSignal(false)
const pathTypeCheck = useSignal<string | null | undefined>('') const pathTypeCheck = useSignal<string | null | undefined>('')

View File

@ -243,6 +243,7 @@ export default function ClipboardHistoryPage() {
isSimplifiedLayout, isSimplifiedLayout,
isSavedClipsPanelVisibleOnly, isSavedClipsPanelVisibleOnly,
isSingleClickToCopyPaste, isSingleClickToCopyPaste,
historyPreviewLineLimit,
} = useAtomValue(settingsStoreAtom) } = useAtomValue(settingsStoreAtom)
const { t } = useTranslation() const { t } = useTranslation()
@ -1522,6 +1523,7 @@ export default function ClipboardHistoryPage() {
isSingleClickToCopyPaste={ isSingleClickToCopyPaste={
isSingleClickToCopyPaste isSingleClickToCopyPaste
} }
historyPreviewLineLimit={historyPreviewLineLimit}
/> />
</Box> </Box>
) )
@ -2148,6 +2150,7 @@ export default function ClipboardHistoryPage() {
isSingleClickToCopyPaste={ isSingleClickToCopyPaste={
isSingleClickToCopyPaste isSingleClickToCopyPaste
} }
historyPreviewLineLimit={historyPreviewLineLimit}
index={index} index={index}
style={style} style={style}
/> />
@ -2208,6 +2211,7 @@ export default function ClipboardHistoryPage() {
activeDragId.toString().split('::pinned')[0] activeDragId.toString().split('::pinned')[0]
})} })}
isSingleClickToCopyPaste={isSingleClickToCopyPaste} isSingleClickToCopyPaste={isSingleClickToCopyPaste}
historyPreviewLineLimit={historyPreviewLineLimit}
/> />
) : null} ) : null}
</DragOverlay> </DragOverlay>

View File

@ -123,6 +123,7 @@ export default function ClipboardHistoryQuickPastePage() {
isQuickPasteAutoClose, isQuickPasteAutoClose,
isSingleClickToCopyPaste, isSingleClickToCopyPaste,
isSingleClickToCopyPasteQuickWindow, isSingleClickToCopyPasteQuickWindow,
historyPreviewLineLimit,
} = useAtomValue(settingsStoreAtom) } = useAtomValue(settingsStoreAtom)
const [historyFilters, setHistoryFilters] = useState<string[]>([]) const [historyFilters, setHistoryFilters] = useState<string[]>([])
@ -851,6 +852,7 @@ export default function ClipboardHistoryQuickPastePage() {
isSingleClickToCopyPaste || isSingleClickToCopyPaste ||
isSingleClickToCopyPasteQuickWindow isSingleClickToCopyPasteQuickWindow
} }
historyPreviewLineLimit={historyPreviewLineLimit}
/> />
) )
})} })}
@ -1050,6 +1052,7 @@ export default function ClipboardHistoryQuickPastePage() {
isSingleClickToCopyPaste || isSingleClickToCopyPaste ||
isSingleClickToCopyPasteQuickWindow isSingleClickToCopyPasteQuickWindow
} }
historyPreviewLineLimit={historyPreviewLineLimit}
index={index} index={index}
style={style} style={style}
/> />

View File

@ -84,8 +84,10 @@ export default function ClipboardHistorySettings() {
isHistoryEnabled, isHistoryEnabled,
clipTextMinLength, clipTextMinLength,
clipTextMaxLength, clipTextMaxLength,
historyPreviewLineLimit,
setClipTextMinLength, setClipTextMinLength,
setClipTextMaxLength, setClipTextMaxLength,
setHistoryPreviewLineLimit,
setIsHistoryEnabled, setIsHistoryEnabled,
isImageCaptureDisabled, isImageCaptureDisabled,
setIsImageCaptureDisabled, setIsImageCaptureDisabled,
@ -357,6 +359,90 @@ export default function ClipboardHistorySettings() {
</Card> </Card>
</Box> </Box>
<Box className="max-w-xl mt-4 animate-in fade-in">
<Card
className={`${
historyPreviewLineLimit == null &&
'opacity-80 bg-gray-100 dark:bg-gray-900/80'
}`}
>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-1">
<CardTitle className="animate-in fade-in text-md font-medium w-full">
{t('History Item Preview Max Lines', {
ns: 'settings2',
})}
</CardTitle>
<Switch
checked={historyPreviewLineLimit !== null}
className="ml-auto"
onCheckedChange={() => {
if (historyPreviewLineLimit) {
setHistoryPreviewLineLimit(null)
} else {
setHistoryPreviewLineLimit(5)
}
}}
/>
</CardHeader>
<CardContent>
<Text className="text-sm text-muted-foreground">
{t(
'Set the maximum number of lines to display in the preview of a history item',
{
ns: 'settings2',
}
)}
</Text>
{historyPreviewLineLimit !== null && (
<>
<Flex className="w-full gap-10 my-4 items-start justify-start">
<InputField
className="text-md !w-36"
type="number"
step="1"
min={1}
max={20}
small
label={t('Preview Max Lines', { ns: 'settings2' })}
value={
historyPreviewLineLimit ? historyPreviewLineLimit : ''
}
onBlur={() => {
if (
historyPreviewLineLimit &&
historyPreviewLineLimit < 0
) {
setHistoryPreviewLineLimit(null)
}
}}
onChange={e => {
const value = e.target.value
if (value === '') {
setHistoryPreviewLineLimit(null)
} else {
const number = parseInt(value, 10)
setHistoryPreviewLineLimit(number)
}
}}
/>
</Flex>
<Button
variant="secondary"
size="sm"
disabled={historyPreviewLineLimit === 5}
onClick={() => {
setHistoryPreviewLineLimit(5)
}}
className="text-sm bg-slate-200 dark:bg-slate-700 dark:text-slate-200 mt-1"
>
{t('Reset', { ns: 'common' })}
</Button>
</>
)}
</CardContent>
</Card>
</Box>
<Box className="max-w-xl animate-in fade-in mt-4"> <Box className="max-w-xl animate-in fade-in mt-4">
<Card <Card
className={`${ className={`${

View File

@ -89,6 +89,7 @@ type Settings = {
isScreenLockPassCodeRequireOnStart: boolean isScreenLockPassCodeRequireOnStart: boolean
clipTextMinLength: number clipTextMinLength: number
clipTextMaxLength: number clipTextMaxLength: number
historyPreviewLineLimit: number | null
isImageCaptureDisabled: boolean isImageCaptureDisabled: boolean
isMenuItemCopyOnlyEnabled: boolean isMenuItemCopyOnlyEnabled: boolean
isNoteIconsEnabled: boolean isNoteIconsEnabled: boolean
@ -215,6 +216,7 @@ export interface SettingsStoreState {
initSettings: (settings: Settings) => void initSettings: (settings: Settings) => void
setClipTextMinLength: (width: number) => void setClipTextMinLength: (width: number) => void
setClipTextMaxLength: (height: number) => void setClipTextMaxLength: (height: number) => void
setHistoryPreviewLineLimit: (limit: number | null) => void
setProtectedCollections: (ids: string[]) => void setProtectedCollections: (ids: string[]) => void
setHasPinProtectedCollections: (hasPinProtectedCollections: boolean) => Promise<void> setHasPinProtectedCollections: (hasPinProtectedCollections: boolean) => Promise<void>
setGlobalTemplatesEnabled: (isEnabled: boolean) => void setGlobalTemplatesEnabled: (isEnabled: boolean) => void
@ -292,6 +294,7 @@ const initialState: SettingsStoreState & Settings = {
isFirstRunAfterUpdate: false, isFirstRunAfterUpdate: false,
clipTextMinLength: 0, clipTextMinLength: 0,
clipTextMaxLength: 5000, clipTextMaxLength: 5000,
historyPreviewLineLimit: 5,
isImageCaptureDisabled: false, isImageCaptureDisabled: false,
isMenuItemCopyOnlyEnabled: false, isMenuItemCopyOnlyEnabled: false,
isNoteIconsEnabled: true, isNoteIconsEnabled: true,
@ -367,6 +370,7 @@ const initialState: SettingsStoreState & Settings = {
setIsShowNavBarItemsOnHoverOnly: () => {}, setIsShowNavBarItemsOnHoverOnly: () => {},
setClipTextMinLength: () => {}, setClipTextMinLength: () => {},
setClipTextMaxLength: () => {}, setClipTextMaxLength: () => {},
setHistoryPreviewLineLimit: () => {},
setIsImageCaptureDisabled: () => {}, setIsImageCaptureDisabled: () => {},
setIsMenuItemCopyOnlyEnabled: () => {}, setIsMenuItemCopyOnlyEnabled: () => {},
setIsNoteIconsEnabled: () => {}, setIsNoteIconsEnabled: () => {},
@ -712,6 +716,13 @@ export const settingsStore = createStore<SettingsStoreState & Settings>()((set,
setClipTextMaxLength: async (length: number) => { setClipTextMaxLength: async (length: number) => {
return get().updateSetting('clipTextMaxLength', length) return get().updateSetting('clipTextMaxLength', length)
}, },
setHistoryPreviewLineLimit: async (limit: number | null) => {
if (limit === 0) {
limit = null
}
get().syncStateUpdate('historyPreviewLineLimit', limit)
return get().updateSetting('historyPreviewLineLimit', limit)
},
setIsImageCaptureDisabled: async (isEnabled: boolean) => { setIsImageCaptureDisabled: async (isEnabled: boolean) => {
return get().updateSetting('isImageCaptureDisabled', isEnabled) return get().updateSetting('isImageCaptureDisabled', isEnabled)
}, },