documentation-hub 5.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +43 -0
- package/.github/workflows/build.yml +64 -0
- package/.github/workflows/ci.yml +39 -0
- package/.vscode/extensions.json +3 -0
- package/Current.md +97 -0
- package/DocHub_Image.png +0 -0
- package/README.md +666 -0
- package/USER_GUIDE.md +1173 -0
- package/Updater.md +311 -0
- package/build/256x256.png +0 -0
- package/build/512x512.png +0 -0
- package/build/app-update.yml +4 -0
- package/build/create-icon.js +208 -0
- package/build/icon.ico +0 -0
- package/build/icon.png +0 -0
- package/build/icon_1024x1024.png +0 -0
- package/dist/assets/Analytics-BpsG9895.js +1 -0
- package/dist/assets/Card-IAZin8kp.js +1 -0
- package/dist/assets/CurrentSession-B-rFkHvf.js +12 -0
- package/dist/assets/Dashboard-C_5gMb0q.js +1 -0
- package/dist/assets/Documents-CqZ25axS.js +1 -0
- package/dist/assets/Input-l89xwXBi.js +1 -0
- package/dist/assets/Reporting-DqdHJY_a.js +1 -0
- package/dist/assets/Search-XNbu5z_3.js +1 -0
- package/dist/assets/SessionManager-lH9hZfzH.js +1 -0
- package/dist/assets/Sessions-ClZOPYNc.js +1 -0
- package/dist/assets/Settings-DUEHGURa.js +11 -0
- package/dist/assets/index-8xUe8ptc.js +24 -0
- package/dist/assets/index-RYyJqF7O.css +1 -0
- package/dist/assets/path-BkOl0AGO.js +1 -0
- package/dist/assets/promises-ID_B9S-h.js +1 -0
- package/dist/assets/urlHelpers-TvgahX0r.js +1 -0
- package/dist/assets/useToast-yRSO1dkm.js +1 -0
- package/dist/assets/vendor-charts-RkGK5ROP.js +36 -0
- package/dist/assets/vendor-db-l0sNRNKZ.js +1 -0
- package/dist/assets/vendor-react-BVZ_anCF.js +4 -0
- package/dist/assets/vendor-search-Dw8P0qyA.js +1 -0
- package/dist/assets/vendor-ui-BU7NfluV.js +53 -0
- package/dist/electron/PowerAutomateApiService-LfW09ZGr.js +147 -0
- package/dist/electron/main-CXkNtyv-.js +19789 -0
- package/dist/electron/main.js +5 -0
- package/dist/electron/preload.js +1 -0
- package/dist/icon.png +0 -0
- package/dist/index.html +27 -0
- package/docs/CODEBASE_ANALYSIS_REPORT.md +309 -0
- package/docs/DEBUG_LOGGING_GUIDE.md +244 -0
- package/docs/README.md +115 -0
- package/docs/TOC_WIRING_GUIDE.md +344 -0
- package/docs/analysis/Bullet_Symbol_Bug_Analysis.md +136 -0
- package/docs/analysis/DOCXMLATER_ANALYSIS_SUMMARY.txt +169 -0
- package/docs/analysis/Document_Processing_Issues_Analysis.md +704 -0
- package/docs/analysis/FIELD_PRESERVATION_ANALYSIS.md +1200 -0
- package/docs/analysis/INDENTATION_PRESERVE_ANALYSIS.md +181 -0
- package/docs/analysis/INDENTATION_PRESERVE_IMPLEMENTATION.md +207 -0
- package/docs/analysis/List_Implementation.md +206 -0
- package/docs/analysis/List_Implementation_Accuracy_Report.md +366 -0
- package/docs/analysis/PROCESSING_OPTIONS_UI_UPDATES.md +220 -0
- package/docs/analysis/RefactorStyles.md +852 -0
- package/docs/analysis/STYLE_PARAMETER_ENHANCEMENT.md +143 -0
- package/docs/analysis/docxmlater-comparison-todo-2025-11-13.md +636 -0
- package/docs/analysis/docxmlater-implementation-analysis-2025-11-13.md +340 -0
- package/docs/analysis/docxmlater-template_ui-integration-analysis.md +263 -0
- package/docs/analysis/github-issues-to-create.md +237 -0
- package/docs/api/API_README.md +538 -0
- package/docs/api/API_REFERENCE.md +751 -0
- package/docs/api/TYPE_DEFINITIONS.md +869 -0
- package/docs/architecture/FONT_EMBEDDING_GUIDE.md +318 -0
- package/docs/architecture/docxmlater-functions-and-structure.md +726 -0
- package/docs/docxmlater-readme.md +1341 -0
- package/docs/fixes/EXECUTION_LOG_TEST_BASE.md +573 -0
- package/docs/fixes/HYPERLINK_TEXT_SANITIZATION.md +253 -0
- package/docs/fixes/README.md +37 -0
- package/docs/github-issues/issue-1-body.md +125 -0
- package/docs/github-issues/issue-10-body.md +850 -0
- package/docs/github-issues/issue-2-body.md +200 -0
- package/docs/github-issues/issue-3-body.md +270 -0
- package/docs/github-issues/issue-4-body.md +169 -0
- package/docs/github-issues/issue-5-body.md +173 -0
- package/docs/github-issues/issue-6-body.md +158 -0
- package/docs/github-issues/issue-7-body.md +171 -0
- package/docs/github-issues/issue-8-body.md +407 -0
- package/docs/github-issues/issue-9-body.md +515 -0
- package/docs/github-issues/issue-tracker.md +274 -0
- package/docs/github-issues/predictive-analysis-2025-10-18.md +2131 -0
- package/docs/implementation/List_Framework_Refactor_Plan.md +336 -0
- package/docs/implementation/PRIMARY_TEXT_COLOR_FEATURE.md +217 -0
- package/docs/implementation/RELEASE_PLAN_v2.1.0.md +362 -0
- package/docs/implementation/RefactorStyles.md +588 -0
- package/docs/implementation/implement-plan.md +489 -0
- package/docs/implementation/missing-helpers-implementation.md +391 -0
- package/docs/implementation/refactor-plan.md +520 -0
- package/docs/implementation/session-implementation-complete.md +233 -0
- package/docs/implementation/session-management-plan.md +250 -0
- package/docs/setup-checklist.md +77 -0
- package/docs/versions/changelog.md +345 -0
- package/electron/customUpdater.ts +656 -0
- package/electron/main.ts +2441 -0
- package/electron/memoryConfig.ts +187 -0
- package/electron/preload.ts +394 -0
- package/electron/proxyConfig.ts +340 -0
- package/electron/services/BackupService.ts +452 -0
- package/electron/services/DictionaryService.ts +402 -0
- package/electron/services/LocalDictionaryLookupService.ts +147 -0
- package/electron/services/PowerAutomateApiService.ts +231 -0
- package/electron/services/SharePointSyncService.ts +474 -0
- package/electron/windowsCertStore.ts +427 -0
- package/electron/zscalerConfig.ts +381 -0
- package/eslint.config.js +92 -0
- package/jest.config.js +52 -0
- package/package.json +214 -0
- package/postcss.config.mjs +6 -0
- package/public/icon.png +0 -0
- package/publish-release.ps1 +5 -0
- package/renovate.json +30 -0
- package/src/App.tsx +216 -0
- package/src/__mocks__/p-limit.js +12 -0
- package/src/__mocks__/styleMock.js +1 -0
- package/src/components/common/BugReportButton.tsx +44 -0
- package/src/components/common/BugReportDialog.tsx +193 -0
- package/src/components/common/Button.tsx +153 -0
- package/src/components/common/Card.tsx +86 -0
- package/src/components/common/ColorPickerDialog.tsx +177 -0
- package/src/components/common/ConfirmDialog.tsx +96 -0
- package/src/components/common/DebugConsole.tsx +275 -0
- package/src/components/common/EmptyState.tsx +183 -0
- package/src/components/common/ErrorBoundary.tsx +98 -0
- package/src/components/common/ErrorDetailsDialog.tsx +153 -0
- package/src/components/common/ErrorFallback.tsx +218 -0
- package/src/components/common/Input.tsx +109 -0
- package/src/components/common/Skeleton.tsx +184 -0
- package/src/components/common/SplashScreen.tsx +81 -0
- package/src/components/common/Toast.tsx +155 -0
- package/src/components/common/Tooltip.tsx +79 -0
- package/src/components/common/UpdateNotification.tsx +320 -0
- package/src/components/comparison/ComparisonWindow.tsx +374 -0
- package/src/components/comparison/SideBySideDiff.tsx +486 -0
- package/src/components/comparison/index.ts +8 -0
- package/src/components/document/DocumentUploader.tsx +288 -0
- package/src/components/document/HyperlinkPreview.tsx +430 -0
- package/src/components/document/HyperlinkService.md +1484 -0
- package/src/components/document/Hyperlink_Technical_Documentation.md +496 -0
- package/src/components/document/InlineChangesView.tsx +707 -0
- package/src/components/document/ProcessingProgress.tsx +303 -0
- package/src/components/document/ProcessingResults.tsx +256 -0
- package/src/components/document/TrackedChangesDetail.tsx +530 -0
- package/src/components/document/TrackedChangesPanel.tsx +546 -0
- package/src/components/document/VirtualDocumentList.tsx +240 -0
- package/src/components/editor/DocumentEditor.tsx +723 -0
- package/src/components/editor/DocumentEditorModal.tsx +640 -0
- package/src/components/editor/EditorQuickActions.tsx +502 -0
- package/src/components/editor/EditorToolbar.tsx +312 -0
- package/src/components/editor/TableEditor.tsx +926 -0
- package/src/components/editor/index.ts +18 -0
- package/src/components/layout/Header.tsx +190 -0
- package/src/components/layout/Sidebar.tsx +313 -0
- package/src/components/layout/TitleBar.tsx +190 -0
- package/src/components/navigation/CommandPalette.tsx +233 -0
- package/src/components/navigation/KeyboardShortcutsModal.tsx +173 -0
- package/src/components/sessions/ChangeItem.tsx +408 -0
- package/src/components/sessions/ChangeViewer.tsx +1155 -0
- package/src/components/sessions/DocumentComparisonModal.tsx +314 -0
- package/src/components/sessions/ProcessingOptions.tsx +297 -0
- package/src/components/sessions/ReplacementsTab.tsx +438 -0
- package/src/components/sessions/RevisionHandlingOptions.tsx +87 -0
- package/src/components/sessions/SessionManager.tsx +188 -0
- package/src/components/sessions/StylesEditor.tsx +1335 -0
- package/src/components/sessions/TabContainer.tsx +151 -0
- package/src/components/sessions/VirtualSessionList.tsx +157 -0
- package/src/components/sessions/sessionToProcessorManager.tsx +420 -0
- package/src/components/settings/CertificateManager.tsx +410 -0
- package/src/components/settings/SegmentedControl.tsx +88 -0
- package/src/components/settings/SettingRow.tsx +52 -0
- package/src/contexts/GlobalStatsContext.tsx +396 -0
- package/src/contexts/SessionContext.tsx +2129 -0
- package/src/contexts/ThemeContext.tsx +428 -0
- package/src/contexts/UserSettingsContext.tsx +290 -0
- package/src/contexts/__tests__/GlobalStatsContext.test.tsx +390 -0
- package/src/global.d.ts +273 -0
- package/src/hooks/useDocumentQueue.tsx +210 -0
- package/src/hooks/useToast.tsx +55 -0
- package/src/main.tsx +10 -0
- package/src/pages/Analytics.tsx +386 -0
- package/src/pages/CurrentSession.tsx +1174 -0
- package/src/pages/Dashboard.tsx +319 -0
- package/src/pages/Documents.tsx +317 -0
- package/src/pages/Projects.tsx +250 -0
- package/src/pages/Reporting.tsx +386 -0
- package/src/pages/Search.tsx +349 -0
- package/src/pages/Sessions.tsx +285 -0
- package/src/pages/Settings.tsx +2662 -0
- package/src/services/HyperlinkService.ts +1085 -0
- package/src/services/document/DocXMLaterProcessor.ts +617 -0
- package/src/services/document/DocumentProcessingComparison.ts +856 -0
- package/src/services/document/DocumentSnapshotService.ts +575 -0
- package/src/services/document/WordDocumentProcessor.ts +10509 -0
- package/src/services/document/__tests__/DocXMLaterProcessor.hyperlinks.test.md +311 -0
- package/src/services/document/__tests__/WordDocumentProcessor.integration.test.ts +515 -0
- package/src/services/document/__tests__/WordDocumentProcessor.test.ts +812 -0
- package/src/services/document/blanklines/BlankLineManager.ts +658 -0
- package/src/services/document/blanklines/__tests__/paragraphChecks.test.ts +281 -0
- package/src/services/document/blanklines/helpers/blankLineInsertion.ts +87 -0
- package/src/services/document/blanklines/helpers/blankLineSnapshot.ts +251 -0
- package/src/services/document/blanklines/helpers/clearCustom.ts +121 -0
- package/src/services/document/blanklines/helpers/contextChecks.ts +117 -0
- package/src/services/document/blanklines/helpers/imageChecks.ts +51 -0
- package/src/services/document/blanklines/helpers/paragraphChecks.ts +236 -0
- package/src/services/document/blanklines/helpers/removeBlanksBetweenListItems.ts +91 -0
- package/src/services/document/blanklines/helpers/removeTrailingBlanks.ts +35 -0
- package/src/services/document/blanklines/helpers/tableGuards.ts +21 -0
- package/src/services/document/blanklines/index.ts +67 -0
- package/src/services/document/blanklines/rules/additionRules.ts +337 -0
- package/src/services/document/blanklines/rules/indentationRules.ts +317 -0
- package/src/services/document/blanklines/rules/removalRules.ts +362 -0
- package/src/services/document/blanklines/rules/ruleTypes.ts +92 -0
- package/src/services/document/blanklines/types.ts +29 -0
- package/src/services/document/helpers/ImageBorderCropper.ts +377 -0
- package/src/services/document/helpers/__tests__/whitespace.test.ts +272 -0
- package/src/services/document/helpers/whitespace.ts +117 -0
- package/src/services/document/list/ListNormalizer.ts +947 -0
- package/src/services/document/list/index.ts +45 -0
- package/src/services/document/list/list-detection.ts +275 -0
- package/src/services/document/list/list-types.ts +162 -0
- package/src/services/document/processors/HyperlinkProcessor.ts +370 -0
- package/src/services/document/processors/ListProcessor.ts +257 -0
- package/src/services/document/processors/StructureProcessor.ts +176 -0
- package/src/services/document/processors/StyleProcessor.ts +389 -0
- package/src/services/document/processors/TableProcessor.ts +2238 -0
- package/src/services/document/processors/__tests__/HyperlinkProcessor.test.ts +314 -0
- package/src/services/document/processors/__tests__/ListProcessor.test.ts +291 -0
- package/src/services/document/processors/__tests__/StructureProcessor.test.ts +257 -0
- package/src/services/document/processors/__tests__/TableProcessor.hlp-tips-bullets.test.ts +459 -0
- package/src/services/document/processors/__tests__/TableProcessor.test.ts +1604 -0
- package/src/services/document/processors/index.ts +28 -0
- package/src/services/document/types/docx-processing.ts +310 -0
- package/src/services/editor/EditorActionHandlers.ts +901 -0
- package/src/services/editor/index.ts +13 -0
- package/src/setupTests.ts +47 -0
- package/src/styles/global.css +782 -0
- package/src/types/backup.ts +132 -0
- package/src/types/dictionary.ts +125 -0
- package/src/types/document-processing.ts +331 -0
- package/src/types/docxmlater-augments.d.ts +142 -0
- package/src/types/editor.ts +280 -0
- package/src/types/electron.ts +340 -0
- package/src/types/globalStats.ts +155 -0
- package/src/types/hyperlink.ts +471 -0
- package/src/types/operations.ts +354 -0
- package/src/types/session.ts +427 -0
- package/src/types/settings.ts +112 -0
- package/src/utils/MemoryMonitor.ts +248 -0
- package/src/utils/cn.ts +6 -0
- package/src/utils/colorConvert.ts +306 -0
- package/src/utils/diffUtils.ts +347 -0
- package/src/utils/documentUtils.ts +202 -0
- package/src/utils/electronGuard.ts +62 -0
- package/src/utils/indexedDB.ts +915 -0
- package/src/utils/logger.ts +717 -0
- package/src/utils/pathSecurity.ts +232 -0
- package/src/utils/pathValidator.ts +236 -0
- package/src/utils/processingTimeEstimator.ts +153 -0
- package/src/utils/safeJsonParse.ts +62 -0
- package/src/utils/textSanitizer.ts +162 -0
- package/src/utils/urlHelpers.ts +304 -0
- package/src/utils/urlPatterns.ts +198 -0
- package/src/utils/urlSanitizer.ts +152 -0
- package/src/vite-env.d.ts +11 -0
- package/tsconfig.electron.json +19 -0
- package/tsconfig.json +36 -0
- package/tsconfig.node.json +12 -0
- package/typedoc.json +45 -0
- package/vite.config.ts +152 -0
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DocumentComparisonModal - Side-by-side comparison of original vs processed documents
|
|
3
|
+
*
|
|
4
|
+
* DEFERRED FEATURE: This component is currently disabled in the UI.
|
|
5
|
+
* The side-by-side comparison feature may be implemented in a future release.
|
|
6
|
+
* See ChangeViewer.tsx for the deferred button implementation.
|
|
7
|
+
*
|
|
8
|
+
* Opens a modal dialog displaying SideBySideDiff for comparing document states
|
|
9
|
+
* before and after processing. Supports navigation between multiple documents.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { useState, useEffect, useCallback } from 'react';
|
|
13
|
+
import * as Dialog from '@radix-ui/react-dialog';
|
|
14
|
+
import {
|
|
15
|
+
X,
|
|
16
|
+
ChevronLeft,
|
|
17
|
+
ChevronRight,
|
|
18
|
+
FileText,
|
|
19
|
+
RefreshCw,
|
|
20
|
+
AlertCircle,
|
|
21
|
+
} from 'lucide-react';
|
|
22
|
+
import { cn } from '@/utils/cn';
|
|
23
|
+
import { Button } from '@/components/common/Button';
|
|
24
|
+
import { SideBySideDiff } from '@/components/comparison/SideBySideDiff';
|
|
25
|
+
import { DocumentSnapshotService } from '@/services/document/DocumentSnapshotService';
|
|
26
|
+
import type { Document } from '@/types/session';
|
|
27
|
+
import logger from '@/utils/logger';
|
|
28
|
+
|
|
29
|
+
interface DocumentComparisonModalProps {
|
|
30
|
+
/** Whether the modal is open */
|
|
31
|
+
isOpen: boolean;
|
|
32
|
+
/** Callback when modal should close */
|
|
33
|
+
onClose: () => void;
|
|
34
|
+
/** Session ID for snapshot lookup */
|
|
35
|
+
sessionId: string;
|
|
36
|
+
/** List of completed documents to compare */
|
|
37
|
+
documents: Document[];
|
|
38
|
+
/** Initial document index to display */
|
|
39
|
+
initialDocumentIndex?: number;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
interface ComparisonState {
|
|
43
|
+
originalText: string[];
|
|
44
|
+
processedText: string[];
|
|
45
|
+
isLoading: boolean;
|
|
46
|
+
error: string | null;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function DocumentComparisonModal({
|
|
50
|
+
isOpen,
|
|
51
|
+
onClose,
|
|
52
|
+
sessionId,
|
|
53
|
+
documents,
|
|
54
|
+
initialDocumentIndex = 0,
|
|
55
|
+
}: DocumentComparisonModalProps) {
|
|
56
|
+
const [currentDocIndex, setCurrentDocIndex] = useState(initialDocumentIndex);
|
|
57
|
+
const [comparisonState, setComparisonState] = useState<ComparisonState>({
|
|
58
|
+
originalText: [],
|
|
59
|
+
processedText: [],
|
|
60
|
+
isLoading: false,
|
|
61
|
+
error: null,
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const currentDoc = documents[currentDocIndex];
|
|
65
|
+
|
|
66
|
+
// Load comparison data for current document
|
|
67
|
+
const loadComparisonData = useCallback(async () => {
|
|
68
|
+
if (!currentDoc || !currentDoc.path) {
|
|
69
|
+
setComparisonState({
|
|
70
|
+
originalText: [],
|
|
71
|
+
processedText: [],
|
|
72
|
+
isLoading: false,
|
|
73
|
+
error: 'Document path not available',
|
|
74
|
+
});
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
setComparisonState((prev) => ({ ...prev, isLoading: true, error: null }));
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
// Load original text from snapshot
|
|
82
|
+
const snapshot = await DocumentSnapshotService.getSnapshot(
|
|
83
|
+
sessionId,
|
|
84
|
+
currentDoc.id
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
if (!snapshot) {
|
|
88
|
+
setComparisonState({
|
|
89
|
+
originalText: [],
|
|
90
|
+
processedText: [],
|
|
91
|
+
isLoading: false,
|
|
92
|
+
error: 'Original document snapshot not available. The snapshot may have expired or was not captured.',
|
|
93
|
+
});
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Load processed text from current document file
|
|
98
|
+
const result = await window.electronAPI.extractDocumentText(currentDoc.path);
|
|
99
|
+
|
|
100
|
+
if (!result.success || !result.textContent) {
|
|
101
|
+
setComparisonState({
|
|
102
|
+
originalText: snapshot.textContent,
|
|
103
|
+
processedText: [],
|
|
104
|
+
isLoading: false,
|
|
105
|
+
error: result.error || 'Failed to extract processed document text',
|
|
106
|
+
});
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
setComparisonState({
|
|
111
|
+
originalText: snapshot.textContent,
|
|
112
|
+
processedText: result.textContent,
|
|
113
|
+
isLoading: false,
|
|
114
|
+
error: null,
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
logger.info(
|
|
118
|
+
`[DocumentComparisonModal] Loaded comparison for ${currentDoc.name}: ` +
|
|
119
|
+
`${snapshot.textContent.length} original paragraphs, ${result.textContent.length} processed paragraphs`
|
|
120
|
+
);
|
|
121
|
+
} catch (error) {
|
|
122
|
+
logger.error('[DocumentComparisonModal] Error loading comparison:', error);
|
|
123
|
+
setComparisonState({
|
|
124
|
+
originalText: [],
|
|
125
|
+
processedText: [],
|
|
126
|
+
isLoading: false,
|
|
127
|
+
error: error instanceof Error ? error.message : 'Failed to load comparison data',
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}, [currentDoc, sessionId]);
|
|
131
|
+
|
|
132
|
+
// Load data when document changes
|
|
133
|
+
useEffect(() => {
|
|
134
|
+
if (isOpen && currentDoc) {
|
|
135
|
+
loadComparisonData();
|
|
136
|
+
}
|
|
137
|
+
}, [isOpen, currentDoc, loadComparisonData]);
|
|
138
|
+
|
|
139
|
+
// Reset state when modal closes
|
|
140
|
+
useEffect(() => {
|
|
141
|
+
if (!isOpen) {
|
|
142
|
+
setCurrentDocIndex(initialDocumentIndex);
|
|
143
|
+
setComparisonState({
|
|
144
|
+
originalText: [],
|
|
145
|
+
processedText: [],
|
|
146
|
+
isLoading: false,
|
|
147
|
+
error: null,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
}, [isOpen, initialDocumentIndex]);
|
|
151
|
+
|
|
152
|
+
// Navigation handlers
|
|
153
|
+
const handlePrevious = useCallback(() => {
|
|
154
|
+
if (currentDocIndex > 0) {
|
|
155
|
+
setCurrentDocIndex((prev) => prev - 1);
|
|
156
|
+
}
|
|
157
|
+
}, [currentDocIndex]);
|
|
158
|
+
|
|
159
|
+
const handleNext = useCallback(() => {
|
|
160
|
+
if (currentDocIndex < documents.length - 1) {
|
|
161
|
+
setCurrentDocIndex((prev) => prev + 1);
|
|
162
|
+
}
|
|
163
|
+
}, [currentDocIndex, documents.length]);
|
|
164
|
+
|
|
165
|
+
// Keyboard navigation
|
|
166
|
+
useEffect(() => {
|
|
167
|
+
if (!isOpen) return;
|
|
168
|
+
|
|
169
|
+
const handleKeyDown = (e: KeyboardEvent) => {
|
|
170
|
+
if (e.key === 'ArrowLeft' && currentDocIndex > 0) {
|
|
171
|
+
handlePrevious();
|
|
172
|
+
} else if (e.key === 'ArrowRight' && currentDocIndex < documents.length - 1) {
|
|
173
|
+
handleNext();
|
|
174
|
+
} else if (e.key === 'Escape') {
|
|
175
|
+
onClose();
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
window.addEventListener('keydown', handleKeyDown);
|
|
180
|
+
return () => window.removeEventListener('keydown', handleKeyDown);
|
|
181
|
+
}, [isOpen, currentDocIndex, documents.length, handlePrevious, handleNext, onClose]);
|
|
182
|
+
|
|
183
|
+
if (documents.length === 0) {
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return (
|
|
188
|
+
<Dialog.Root open={isOpen} onOpenChange={(open) => !open && onClose()}>
|
|
189
|
+
<Dialog.Portal>
|
|
190
|
+
<Dialog.Overlay className="fixed inset-0 bg-black/60 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 z-50" />
|
|
191
|
+
<Dialog.Content
|
|
192
|
+
aria-describedby={undefined}
|
|
193
|
+
className={cn(
|
|
194
|
+
'fixed left-[50%] top-[50%] z-50 translate-x-[-50%] translate-y-[-50%]',
|
|
195
|
+
'w-[95vw] max-w-6xl h-[90vh] rounded-lg border border-border bg-card shadow-xl',
|
|
196
|
+
'flex flex-col overflow-hidden',
|
|
197
|
+
'data-[state=open]:animate-in data-[state=closed]:animate-out',
|
|
198
|
+
'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
|
|
199
|
+
'data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95',
|
|
200
|
+
'data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%]',
|
|
201
|
+
'data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%]'
|
|
202
|
+
)}
|
|
203
|
+
>
|
|
204
|
+
{/* Header */}
|
|
205
|
+
<div className="flex items-center justify-between px-4 py-3 border-b border-border bg-muted/30">
|
|
206
|
+
<div className="flex items-center gap-3">
|
|
207
|
+
<FileText className="w-5 h-5 text-primary" />
|
|
208
|
+
<Dialog.Title className="font-semibold text-foreground">
|
|
209
|
+
Compare: {currentDoc?.name || 'Document'}
|
|
210
|
+
</Dialog.Title>
|
|
211
|
+
</div>
|
|
212
|
+
|
|
213
|
+
<div className="flex items-center gap-4">
|
|
214
|
+
{/* Navigation */}
|
|
215
|
+
{documents.length > 1 && (
|
|
216
|
+
<div className="flex items-center gap-2">
|
|
217
|
+
<Button
|
|
218
|
+
variant="ghost"
|
|
219
|
+
size="sm"
|
|
220
|
+
onClick={handlePrevious}
|
|
221
|
+
disabled={currentDocIndex === 0}
|
|
222
|
+
className="h-8 w-8 p-0"
|
|
223
|
+
title="Previous document (Left Arrow)"
|
|
224
|
+
>
|
|
225
|
+
<ChevronLeft className="w-4 h-4" />
|
|
226
|
+
</Button>
|
|
227
|
+
<span className="text-sm text-muted-foreground min-w-[4rem] text-center">
|
|
228
|
+
{currentDocIndex + 1} / {documents.length}
|
|
229
|
+
</span>
|
|
230
|
+
<Button
|
|
231
|
+
variant="ghost"
|
|
232
|
+
size="sm"
|
|
233
|
+
onClick={handleNext}
|
|
234
|
+
disabled={currentDocIndex === documents.length - 1}
|
|
235
|
+
className="h-8 w-8 p-0"
|
|
236
|
+
title="Next document (Right Arrow)"
|
|
237
|
+
>
|
|
238
|
+
<ChevronRight className="w-4 h-4" />
|
|
239
|
+
</Button>
|
|
240
|
+
</div>
|
|
241
|
+
)}
|
|
242
|
+
|
|
243
|
+
{/* Close button */}
|
|
244
|
+
<Dialog.Close asChild>
|
|
245
|
+
<Button
|
|
246
|
+
variant="ghost"
|
|
247
|
+
size="sm"
|
|
248
|
+
className="h-8 w-8 p-0"
|
|
249
|
+
title="Close (Escape)"
|
|
250
|
+
>
|
|
251
|
+
<X className="w-4 h-4" />
|
|
252
|
+
</Button>
|
|
253
|
+
</Dialog.Close>
|
|
254
|
+
</div>
|
|
255
|
+
</div>
|
|
256
|
+
|
|
257
|
+
{/* Content */}
|
|
258
|
+
<div className="flex-1 overflow-hidden">
|
|
259
|
+
{comparisonState.isLoading ? (
|
|
260
|
+
<div className="flex flex-col items-center justify-center h-full text-muted-foreground">
|
|
261
|
+
<RefreshCw className="w-10 h-10 mb-4 animate-spin" />
|
|
262
|
+
<p className="text-lg font-medium">Loading comparison data...</p>
|
|
263
|
+
<p className="text-sm mt-1">Extracting document content</p>
|
|
264
|
+
</div>
|
|
265
|
+
) : comparisonState.error ? (
|
|
266
|
+
<div className="flex flex-col items-center justify-center h-full text-muted-foreground">
|
|
267
|
+
<AlertCircle className="w-10 h-10 mb-4 text-destructive" />
|
|
268
|
+
<p className="text-lg font-medium text-destructive">Unable to load comparison</p>
|
|
269
|
+
<p className="text-sm mt-2 max-w-md text-center">{comparisonState.error}</p>
|
|
270
|
+
<Button
|
|
271
|
+
variant="outline"
|
|
272
|
+
size="sm"
|
|
273
|
+
className="mt-4"
|
|
274
|
+
onClick={loadComparisonData}
|
|
275
|
+
>
|
|
276
|
+
<RefreshCw className="w-4 h-4 mr-2" />
|
|
277
|
+
Retry
|
|
278
|
+
</Button>
|
|
279
|
+
</div>
|
|
280
|
+
) : (
|
|
281
|
+
<SideBySideDiff
|
|
282
|
+
originalContent={comparisonState.originalText}
|
|
283
|
+
modifiedContent={comparisonState.processedText}
|
|
284
|
+
syncScroll={true}
|
|
285
|
+
showLineNumbers={true}
|
|
286
|
+
collapseUnchanged={false}
|
|
287
|
+
height="100%"
|
|
288
|
+
/>
|
|
289
|
+
)}
|
|
290
|
+
</div>
|
|
291
|
+
|
|
292
|
+
{/* Footer */}
|
|
293
|
+
<div className="flex items-center justify-between px-4 py-2 border-t border-border bg-muted/20 text-xs text-muted-foreground">
|
|
294
|
+
<div>
|
|
295
|
+
Original: {comparisonState.originalText.length} paragraphs |
|
|
296
|
+
Processed: {comparisonState.processedText.length} paragraphs
|
|
297
|
+
</div>
|
|
298
|
+
<div className="flex items-center gap-2">
|
|
299
|
+
<span className="px-2 py-0.5 rounded bg-red-100 dark:bg-red-900/30 text-red-700 dark:text-red-300">
|
|
300
|
+
Removed
|
|
301
|
+
</span>
|
|
302
|
+
<span className="px-2 py-0.5 rounded bg-green-100 dark:bg-green-900/30 text-green-700 dark:text-green-300">
|
|
303
|
+
Added
|
|
304
|
+
</span>
|
|
305
|
+
<span className="px-2 py-0.5 rounded bg-yellow-100 dark:bg-yellow-900/30 text-yellow-700 dark:text-yellow-300">
|
|
306
|
+
Modified
|
|
307
|
+
</span>
|
|
308
|
+
</div>
|
|
309
|
+
</div>
|
|
310
|
+
</Dialog.Content>
|
|
311
|
+
</Dialog.Portal>
|
|
312
|
+
</Dialog.Root>
|
|
313
|
+
);
|
|
314
|
+
}
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import { cn } from '@/utils/cn';
|
|
2
|
+
import { motion } from 'framer-motion';
|
|
3
|
+
import { Check } from 'lucide-react';
|
|
4
|
+
import { useCallback, useMemo } from 'react';
|
|
5
|
+
import { RevisionHandlingOptions } from './RevisionHandlingOptions';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* TYPE SAFETY: Define processing groups as const tuple for runtime validation
|
|
9
|
+
* This allows us to derive the type from the value, ensuring consistency
|
|
10
|
+
* between runtime checks and TypeScript types.
|
|
11
|
+
*/
|
|
12
|
+
export const PROCESSING_GROUPS = ['text', 'hyperlinks', 'structure', 'lists'] as const;
|
|
13
|
+
export type ProcessingGroup = (typeof PROCESSING_GROUPS)[number];
|
|
14
|
+
|
|
15
|
+
export interface ProcessingOption {
|
|
16
|
+
id: string;
|
|
17
|
+
label: string;
|
|
18
|
+
group: ProcessingGroup;
|
|
19
|
+
enabled: boolean;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// User-friendly descriptions for the right panel
|
|
23
|
+
const optionDescriptions: Record<string, string> = {
|
|
24
|
+
// Text Formatting
|
|
25
|
+
'remove-italics': 'Removes all italic text formatting',
|
|
26
|
+
'normalize-dashes': 'Converts special dashes (em-dash, en-dash) to regular hyphens',
|
|
27
|
+
'preserve-red-font': 'Prevents changes to text that is colored red',
|
|
28
|
+
'replace-outdated-titles': 'Updates a hyperlink\'s display text to match the title within theSource if different',
|
|
29
|
+
'validate-document-styles': 'Applies your custom style settings from the Styles tab',
|
|
30
|
+
'correct-misapplied-styles': 'Fixes paragraphs with incorrectly applied TOC or Hyperlink styles so they receive proper formatting',
|
|
31
|
+
|
|
32
|
+
// Links & Navigation
|
|
33
|
+
'update-top-hyperlinks': 'Adds or updates links that jump to the document start',
|
|
34
|
+
'update-toc-hyperlinks': 'Creates or updates clickable links in the table of contents',
|
|
35
|
+
'force-remove-heading1-toc': 'Removes the main document title from the table of contents',
|
|
36
|
+
'fix-internal-hyperlinks': 'Fixes broken links that point to other parts of the document',
|
|
37
|
+
'fix-content-ids': 'Appends Content ID to the end of theSource Hyperlinks',
|
|
38
|
+
|
|
39
|
+
// Document Structure
|
|
40
|
+
'center-border-images': 'Centers and borders images if image is bigger than 100x100 pixels',
|
|
41
|
+
'remove-whitespace': 'Removes unnecessary spaces, tabs, and blank areas',
|
|
42
|
+
'remove-paragraph-lines': 'Makes spacing between paragraphs consistent',
|
|
43
|
+
'remove-headers-footers': 'Removes text from document headers and footers',
|
|
44
|
+
'add-document-warning': 'Adds a standard disclaimer notice if missing',
|
|
45
|
+
'validate-header2-tables': 'Formats 1x1 Heading 2 tables to ensure standardization across document',
|
|
46
|
+
|
|
47
|
+
// Lists & Tables
|
|
48
|
+
'list-indentation': 'Corrects the indentation of bulleted and numbered lists',
|
|
49
|
+
'bullet-uniformity': 'Makes bullet styles consistent throughout',
|
|
50
|
+
'normalize-table-lists': 'Converts typed list prefixes (1., A., •) to proper Word formatting and fixes mixed lists',
|
|
51
|
+
'smart-tables': 'Applies consistent styling to all tables',
|
|
52
|
+
'adjust-table-padding': 'Adjusts the space inside table cells',
|
|
53
|
+
'standardize-table-borders': 'Makes table border styles uniform',
|
|
54
|
+
'set-landscape-margins': 'Sets document to landscape orientation with 1-inch margins',
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export const defaultOptions: ProcessingOption[] = [
|
|
58
|
+
// Text Formatting Group
|
|
59
|
+
{ id: 'remove-italics', label: 'Remove Italics', group: 'text', enabled: true },
|
|
60
|
+
{ id: 'normalize-dashes', label: 'Standardize Dashes', group: 'text', enabled: true },
|
|
61
|
+
{ id: 'preserve-red-font', label: 'Keep Red Text', group: 'text', enabled: false },
|
|
62
|
+
{ id: 'replace-outdated-titles', label: 'Update theSource Link Titles', group: 'hyperlinks', enabled: true },
|
|
63
|
+
{ id: 'validate-document-styles', label: 'Apply Custom Styles', group: 'text', enabled: true },
|
|
64
|
+
{ id: 'correct-misapplied-styles', label: 'Fix Misapplied Styles', group: 'text', enabled: true },
|
|
65
|
+
|
|
66
|
+
// Links & Navigation Group
|
|
67
|
+
{ id: 'update-top-hyperlinks', label: '"Top of Document" Hyperlinks', group: 'hyperlinks', enabled: true },
|
|
68
|
+
{ id: 'update-toc-hyperlinks', label: 'Table of Contents Hyperlinks', group: 'hyperlinks', enabled: true },
|
|
69
|
+
{ id: 'force-remove-heading1-toc', label: 'Remove Title from TOC', group: 'hyperlinks', enabled: true },
|
|
70
|
+
{ id: 'fix-internal-hyperlinks', label: 'Internal Hyperlinks', group: 'hyperlinks', enabled: true },
|
|
71
|
+
{ id: 'fix-content-ids', label: 'Content ID References', group: 'hyperlinks', enabled: true },
|
|
72
|
+
|
|
73
|
+
// Document Structure Group
|
|
74
|
+
{ id: 'center-border-images', label: 'Center and Border Images', group: 'structure', enabled: true },
|
|
75
|
+
{ id: 'remove-whitespace', label: 'Clean Up Spaces', group: 'structure', enabled: true },
|
|
76
|
+
{ id: 'remove-paragraph-lines', label: 'Standardize Blank Lines', group: 'structure', enabled: true },
|
|
77
|
+
{ id: 'remove-headers-footers', label: 'Clear Headers/Footers', group: 'structure', enabled: true },
|
|
78
|
+
{ id: 'add-document-warning', label: 'Add Missing Disclaimer', group: 'structure', enabled: true },
|
|
79
|
+
{ id: 'validate-header2-tables', label: 'Heading 2 Tables', group: 'structure', enabled: true },
|
|
80
|
+
{ id: 'set-landscape-margins', label: 'Landscape Layout', group: 'structure', enabled: true },
|
|
81
|
+
|
|
82
|
+
// Lists & Tables Group
|
|
83
|
+
{ id: 'list-indentation', label: 'Fix List Spacing', group: 'lists', enabled: true },
|
|
84
|
+
{ id: 'bullet-uniformity', label: 'Standardize Bullets', group: 'lists', enabled: true },
|
|
85
|
+
{ id: 'normalize-table-lists', label: 'Fix Typed List Prefixes', group: 'lists', enabled: true },
|
|
86
|
+
{ id: 'smart-tables', label: 'Format Tables', group: 'lists', enabled: true },
|
|
87
|
+
{ id: 'adjust-table-padding', label: 'Table Cell Spacing', group: 'lists', enabled: true },
|
|
88
|
+
{ id: 'standardize-table-borders', label: 'Fix Table Borders', group: 'lists', enabled: true },
|
|
89
|
+
];
|
|
90
|
+
|
|
91
|
+
// User-friendly group labels
|
|
92
|
+
const groupLabels: Record<ProcessingGroup, string> = {
|
|
93
|
+
text: 'Text Formatting',
|
|
94
|
+
hyperlinks: 'Links & Navigation',
|
|
95
|
+
structure: 'Document Structure',
|
|
96
|
+
lists: 'Lists & Tables',
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
interface ProcessingOptionsProps {
|
|
100
|
+
sessionId?: string;
|
|
101
|
+
options: ProcessingOption[]; // Fully controlled - no "initial" prefix
|
|
102
|
+
onOptionsChange: (options: ProcessingOption[]) => void; // Required, not optional
|
|
103
|
+
// Revision handling options
|
|
104
|
+
autoAcceptRevisions?: boolean;
|
|
105
|
+
onAutoAcceptRevisionsChange?: (autoAccept: boolean) => void;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function ProcessingOptions({
|
|
109
|
+
options,
|
|
110
|
+
onOptionsChange,
|
|
111
|
+
autoAcceptRevisions = false,
|
|
112
|
+
onAutoAcceptRevisionsChange,
|
|
113
|
+
}: ProcessingOptionsProps) {
|
|
114
|
+
// Calculate master toggle state from props (derived state, not stored)
|
|
115
|
+
const masterToggle = useMemo(() => {
|
|
116
|
+
return options.every((opt) => opt.enabled);
|
|
117
|
+
}, [options]);
|
|
118
|
+
|
|
119
|
+
const toggleOption = useCallback(
|
|
120
|
+
(optionId: string) => {
|
|
121
|
+
const updatedOptions = options.map((opt) =>
|
|
122
|
+
opt.id === optionId ? { ...opt, enabled: !opt.enabled } : opt
|
|
123
|
+
);
|
|
124
|
+
onOptionsChange(updatedOptions);
|
|
125
|
+
},
|
|
126
|
+
[options, onOptionsChange]
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
const toggleAll = useCallback(() => {
|
|
130
|
+
const newState = !masterToggle;
|
|
131
|
+
const updatedOptions = options.map((opt) => ({ ...opt, enabled: newState }));
|
|
132
|
+
onOptionsChange(updatedOptions);
|
|
133
|
+
}, [masterToggle, options, onOptionsChange]);
|
|
134
|
+
|
|
135
|
+
const toggleGroup = useCallback(
|
|
136
|
+
(group: string) => {
|
|
137
|
+
const groupOptions = options.filter((opt) => opt.group === group);
|
|
138
|
+
const allEnabled = groupOptions.every((opt) => opt.enabled);
|
|
139
|
+
|
|
140
|
+
const updatedOptions = options.map((opt) =>
|
|
141
|
+
opt.group === group ? { ...opt, enabled: !allEnabled } : opt
|
|
142
|
+
);
|
|
143
|
+
onOptionsChange(updatedOptions);
|
|
144
|
+
},
|
|
145
|
+
[options, onOptionsChange]
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
const groupedOptions = options.reduce(
|
|
149
|
+
(acc, option) => {
|
|
150
|
+
if (!acc[option.group]) {
|
|
151
|
+
acc[option.group] = [];
|
|
152
|
+
}
|
|
153
|
+
acc[option.group].push(option);
|
|
154
|
+
return acc;
|
|
155
|
+
},
|
|
156
|
+
{} as Record<string, ProcessingOption[]>
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
// Get enabled options grouped by category for the right panel
|
|
160
|
+
const enabledByGroup = useMemo(() => {
|
|
161
|
+
const result: Record<string, ProcessingOption[]> = {};
|
|
162
|
+
for (const group of PROCESSING_GROUPS) {
|
|
163
|
+
const enabledInGroup = options.filter((opt) => opt.group === group && opt.enabled);
|
|
164
|
+
if (enabledInGroup.length > 0) {
|
|
165
|
+
result[group] = enabledInGroup;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return result;
|
|
169
|
+
}, [options]);
|
|
170
|
+
|
|
171
|
+
const hasEnabledOptions = Object.keys(enabledByGroup).length > 0;
|
|
172
|
+
|
|
173
|
+
return (
|
|
174
|
+
<div className="space-y-6">
|
|
175
|
+
{/* Two-Column Layout: Options on Left, Descriptions on Right */}
|
|
176
|
+
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
|
177
|
+
{/* Left Column: Options */}
|
|
178
|
+
<div className="space-y-4">
|
|
179
|
+
{Object.entries(groupedOptions).map(([group, groupOptions]) => {
|
|
180
|
+
const allEnabled = groupOptions.every((opt) => opt.enabled);
|
|
181
|
+
const someEnabled = groupOptions.some((opt) => opt.enabled);
|
|
182
|
+
|
|
183
|
+
return (
|
|
184
|
+
<div key={group} className="space-y-2">
|
|
185
|
+
<button
|
|
186
|
+
type="button"
|
|
187
|
+
className="flex items-center gap-2 cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 rounded"
|
|
188
|
+
onClick={() => toggleGroup(group)}
|
|
189
|
+
role="checkbox"
|
|
190
|
+
aria-checked={allEnabled ? true : someEnabled ? 'mixed' : false}
|
|
191
|
+
aria-label={`Toggle ${groupLabels[group as ProcessingGroup]}`}
|
|
192
|
+
>
|
|
193
|
+
<div
|
|
194
|
+
aria-hidden="true"
|
|
195
|
+
className={cn(
|
|
196
|
+
'w-5 h-5 rounded border-2 flex items-center justify-center transition-all',
|
|
197
|
+
allEnabled
|
|
198
|
+
? 'bg-primary border-primary checkbox-checked'
|
|
199
|
+
: someEnabled
|
|
200
|
+
? 'bg-primary/50 border-primary'
|
|
201
|
+
: 'border-border hover:border-primary/50'
|
|
202
|
+
)}
|
|
203
|
+
>
|
|
204
|
+
{(allEnabled || someEnabled) && (
|
|
205
|
+
<Check className="w-3 h-3 text-primary-foreground checkbox-checkmark" />
|
|
206
|
+
)}
|
|
207
|
+
</div>
|
|
208
|
+
<span className="font-semibold text-sm">
|
|
209
|
+
{groupLabels[group as ProcessingGroup]}
|
|
210
|
+
</span>
|
|
211
|
+
</button>
|
|
212
|
+
|
|
213
|
+
<div className="pl-5 space-y-1">
|
|
214
|
+
{groupOptions.map((option) => (
|
|
215
|
+
<label key={option.id} className="flex items-center gap-2 cursor-pointer group">
|
|
216
|
+
<div className="relative">
|
|
217
|
+
<input
|
|
218
|
+
type="checkbox"
|
|
219
|
+
checked={option.enabled}
|
|
220
|
+
onChange={() => toggleOption(option.id)}
|
|
221
|
+
className="sr-only"
|
|
222
|
+
/>
|
|
223
|
+
<div
|
|
224
|
+
className={cn(
|
|
225
|
+
'w-4 h-4 rounded border-2 flex items-center justify-center transition-all',
|
|
226
|
+
option.enabled
|
|
227
|
+
? 'bg-primary border-primary checkbox-checked'
|
|
228
|
+
: 'border-border group-hover:border-primary/50'
|
|
229
|
+
)}
|
|
230
|
+
>
|
|
231
|
+
{option.enabled && (
|
|
232
|
+
<motion.div
|
|
233
|
+
initial={{ scale: 0 }}
|
|
234
|
+
animate={{ scale: 1 }}
|
|
235
|
+
transition={{ type: 'spring', stiffness: 500, damping: 30 }}
|
|
236
|
+
>
|
|
237
|
+
<Check className="w-2.5 h-2.5 text-primary-foreground checkbox-checkmark" />
|
|
238
|
+
</motion.div>
|
|
239
|
+
)}
|
|
240
|
+
</div>
|
|
241
|
+
</div>
|
|
242
|
+
<span className="text-sm">{option.label}</span>
|
|
243
|
+
</label>
|
|
244
|
+
))}
|
|
245
|
+
</div>
|
|
246
|
+
</div>
|
|
247
|
+
);
|
|
248
|
+
})}
|
|
249
|
+
</div>
|
|
250
|
+
|
|
251
|
+
{/* Right Column: Enabled Processing Descriptions */}
|
|
252
|
+
<div className="bg-muted/20 rounded-lg p-4 border border-border/50">
|
|
253
|
+
<h4 className="font-medium text-sm mb-3 text-muted-foreground">Enabled processing:</h4>
|
|
254
|
+
|
|
255
|
+
{hasEnabledOptions ? (
|
|
256
|
+
<div className="space-y-4">
|
|
257
|
+
{Object.entries(enabledByGroup).map(([group, groupOptions]) => (
|
|
258
|
+
<div key={group}>
|
|
259
|
+
<h5 className="text-xs font-semibold text-muted-foreground uppercase tracking-wide mb-2">
|
|
260
|
+
{groupLabels[group as ProcessingGroup]}
|
|
261
|
+
</h5>
|
|
262
|
+
<ul className="space-y-1.5">
|
|
263
|
+
{groupOptions.map((option) => (
|
|
264
|
+
<motion.li
|
|
265
|
+
key={option.id}
|
|
266
|
+
initial={{ opacity: 0, x: -10 }}
|
|
267
|
+
animate={{ opacity: 1, x: 0 }}
|
|
268
|
+
exit={{ opacity: 0, x: -10 }}
|
|
269
|
+
className="flex items-start gap-2 text-sm"
|
|
270
|
+
>
|
|
271
|
+
<span className="text-primary mt-0.5">•</span>
|
|
272
|
+
<span>{optionDescriptions[option.id]}</span>
|
|
273
|
+
</motion.li>
|
|
274
|
+
))}
|
|
275
|
+
</ul>
|
|
276
|
+
</div>
|
|
277
|
+
))}
|
|
278
|
+
</div>
|
|
279
|
+
) : (
|
|
280
|
+
<p className="text-sm text-muted-foreground italic">No processing options enabled</p>
|
|
281
|
+
)}
|
|
282
|
+
</div>
|
|
283
|
+
</div>
|
|
284
|
+
|
|
285
|
+
{/* DO NOT REMOVE - May utilize this in the future.
|
|
286
|
+
{onAutoAcceptRevisionsChange && (
|
|
287
|
+
<div className="pt-4 border-t border-border">
|
|
288
|
+
<RevisionHandlingOptions
|
|
289
|
+
autoAccept={autoAcceptRevisions}
|
|
290
|
+
onAutoAcceptChange={onAutoAcceptRevisionsChange}
|
|
291
|
+
/>
|
|
292
|
+
</div>
|
|
293
|
+
)}
|
|
294
|
+
*/}
|
|
295
|
+
</div>
|
|
296
|
+
);
|
|
297
|
+
}
|