diff --git a/CHANGELOG.md b/CHANGELOG.md index 5298649..9b892bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +### Added +- HTML clipboard detection for text sources (#426) + - When pasting content, automatically detects HTML format (e.g., from Word, web pages) + - Shows info message when HTML is detected, informing user it will be converted to Markdown + - Preserves formatting that would be lost with plain text paste + - Bump content-core to 0.11.0 for HTML to Markdown conversion support + ## [1.6.2] - 2026-01-24 ### Fixed diff --git a/frontend/src/components/sources/AddSourceDialog.tsx b/frontend/src/components/sources/AddSourceDialog.tsx index 195b542..a49b2d4 100644 --- a/frontend/src/components/sources/AddSourceDialog.tsx +++ b/frontend/src/components/sources/AddSourceDialog.tsx @@ -126,6 +126,7 @@ export function AddSourceDialog({ handleSubmit, control, watch, + setValue, formState: { errors }, reset, } = useForm({ @@ -553,6 +554,7 @@ export function AddSourceDialog({ // @ts-expect-error - Type inference issue with zod schema control={control} register={register} + setValue={setValue} // @ts-expect-error - Type inference issue with zod schema errors={errors} urlValidationErrors={urlValidationErrors} diff --git a/frontend/src/components/sources/steps/SourceTypeStep.tsx b/frontend/src/components/sources/steps/SourceTypeStep.tsx index 349ff2c..a4c4756 100644 --- a/frontend/src/components/sources/steps/SourceTypeStep.tsx +++ b/frontend/src/components/sources/steps/SourceTypeStep.tsx @@ -1,7 +1,7 @@ "use client" -import { useMemo } from "react" -import { Control, FieldErrors, UseFormRegister, useWatch } from "react-hook-form" +import { useMemo, useState } from "react" +import { Control, FieldErrors, UseFormRegister, UseFormSetValue, useWatch } from "react-hook-form" import { FileIcon, LinkIcon, FileTextIcon } from "lucide-react" import { useTranslation } from "@/lib/hooks/use-translation" import { FormSection } from "@/components/ui/form-section" @@ -89,6 +89,7 @@ const getSourceTypes = (t: TranslationKeys) => [ interface SourceTypeStepProps { control: Control register: UseFormRegister + setValue: UseFormSetValue errors: FieldErrors urlValidationErrors?: { url: string; line: number }[] onClearUrlErrors?: () => void @@ -96,13 +97,39 @@ interface SourceTypeStepProps { const MAX_BATCH_SIZE = 50 -export function SourceTypeStep({ control, register, errors, urlValidationErrors, onClearUrlErrors }: SourceTypeStepProps) { +export function SourceTypeStep({ control, register, setValue, errors, urlValidationErrors, onClearUrlErrors }: SourceTypeStepProps) { const { t } = useTranslation() // Watch the selected type and inputs to detect batch mode const selectedType = useWatch({ control, name: 'type' }) const urlInput = useWatch({ control, name: 'url' }) const fileInput = useWatch({ control, name: 'file' }) + // Track if HTML content was pasted + const [hasHtmlContent, setHasHtmlContent] = useState(false) + + // Handle paste event to check for HTML content in clipboard + const handleTextPaste = (event: React.ClipboardEvent) => { + const htmlContent = event.clipboardData.getData('text/html') + + // If HTML content is available, use it instead of plain text + if (htmlContent) { + event.preventDefault() + // Get current content and cursor position + const textarea = event.currentTarget + const start = textarea.selectionStart + const end = textarea.selectionEnd + const currentValue = textarea.value + + // Insert HTML content at cursor position (replacing selection if any) + const newValue = currentValue.substring(0, start) + htmlContent + currentValue.substring(end) + setValue('content', newValue, { shouldValidate: true }) + setHasHtmlContent(true) + } else { + // Plain text paste - clear the HTML indicator + setHasHtmlContent(false) + } + } + // Batch mode detection const { isBatchMode, itemCount, urlCount, fileCount } = useMemo(() => { let urlCount = 0 @@ -258,11 +285,19 @@ export function SourceTypeStep({ control, register, errors, urlValidationErrors, {type.value === 'text' && (
+ {hasHtmlContent && ( +
+

+ {t.sources.htmlDetected} +

+
+ )}