Restructure frontend code to allow for extensions (#4721)

# Description of Changes
Move frontend code into `core` folder and add infrastructure for
`proprietary` folder to include premium, non-OSS features
This commit is contained in:
James Brunton
2025-10-28 10:29:36 +00:00
committed by GitHub
parent 960d48f80c
commit d2b38ef4b8
725 changed files with 2485 additions and 2226 deletions
@@ -0,0 +1,62 @@
/**
* SplitAutomationSettings - Used for automation only
*
* Combines split method selection and method-specific settings
* into a single component for automation workflows.
*/
import { Stack, Text, Select } from "@mantine/core";
import { useTranslation } from "react-i18next";
import { SplitParameters } from "@app/hooks/tools/split/useSplitParameters";
import { METHOD_OPTIONS, SplitMethod } from "@app/constants/splitConstants";
import SplitSettings from "@app/components/tools/split/SplitSettings";
interface SplitAutomationSettingsProps {
parameters: SplitParameters;
onParameterChange: <K extends keyof SplitParameters>(key: K, value: SplitParameters[K]) => void;
disabled?: boolean;
}
const SplitAutomationSettings = ({ parameters, onParameterChange, disabled = false }: SplitAutomationSettingsProps) => {
const { t } = useTranslation();
// Convert METHOD_OPTIONS to Select data format
const methodSelectOptions = METHOD_OPTIONS.map((option) => {
const prefix = t(option.prefixKey, "Split");
const name = t(option.nameKey, "Method");
return {
value: option.value,
label: `${prefix} ${name}`,
};
});
return (
<Stack gap="lg">
{/* Method Selection */}
<Select
label={t("split.steps.chooseMethod", "Choose Method")}
placeholder={t("split.selectMethod", "Select a split method")}
value={parameters.method}
onChange={(value) => onParameterChange('method', value as (SplitMethod | '') || '')}
data={methodSelectOptions}
disabled={disabled}
/>
{/* Method-Specific Settings */}
{parameters.method && (
<>
<Text size="sm" fw={500}>
{t("split.steps.settings", "Settings")}
</Text>
<SplitSettings
parameters={parameters}
onParameterChange={onParameterChange}
disabled={disabled}
/>
</>
)}
</Stack>
);
};
export default SplitAutomationSettings;
@@ -0,0 +1,163 @@
import { Stack, TextInput, Checkbox, Anchor, Text } from '@mantine/core';
import LocalIcon from '@app/components/shared/LocalIcon';
import { useTranslation } from 'react-i18next';
import { SPLIT_METHODS } from '@app/constants/splitConstants';
import { SplitParameters } from '@app/hooks/tools/split/useSplitParameters';
export interface SplitSettingsProps {
parameters: SplitParameters;
onParameterChange: <K extends keyof SplitParameters>(key: K, value: SplitParameters[K]) => void;
disabled?: boolean;
}
const SplitSettings = ({
parameters,
onParameterChange,
disabled = false
}: SplitSettingsProps) => {
const { t } = useTranslation();
const renderByPagesForm = () => (
<TextInput
label={t("split.splitPages", "Pages")}
placeholder={t("pageSelectionPrompt", "e.g. 1,3,5-10")}
value={parameters.pages}
onChange={(e) => onParameterChange('pages', e.target.value)}
disabled={disabled}
/>
);
const renderBySectionsForm = () => (
<Stack gap="sm">
<TextInput
label={t("split-by-sections.horizontal.label", "Horizontal Divisions")}
type="number"
min="0"
max="300"
value={parameters.hDiv}
onChange={(e) => onParameterChange('hDiv', e.target.value)}
placeholder={t("split-by-sections.horizontal.placeholder", "Enter number of horizontal divisions")}
disabled={disabled}
/>
<TextInput
label={t("split-by-sections.vertical.label", "Vertical Divisions")}
type="number"
min="0"
max="300"
value={parameters.vDiv}
onChange={(e) => onParameterChange('vDiv', e.target.value)}
placeholder={t("split-by-sections.vertical.placeholder", "Enter number of vertical divisions")}
disabled={disabled}
/>
<Checkbox
label={t("split-by-sections.merge", "Merge sections into one PDF")}
checked={parameters.merge}
onChange={(e) => onParameterChange('merge', e.currentTarget.checked)}
disabled={disabled}
/>
</Stack>
);
const renderSplitValueForm = () => {
let label, placeholder;
switch (parameters.method) {
case SPLIT_METHODS.BY_SIZE:
label = t("split.value.fileSize.label", "File Size");
placeholder = t("split.value.fileSize.placeholder", "e.g. 10MB, 500KB");
break;
case SPLIT_METHODS.BY_PAGE_COUNT:
label = t("split.value.pageCount.label", "Pages per File");
placeholder = t("split.value.pageCount.placeholder", "e.g. 5, 10");
break;
case SPLIT_METHODS.BY_DOC_COUNT:
label = t("split.value.docCount.label", "Number of Files");
placeholder = t("split.value.docCount.placeholder", "e.g. 3, 5");
break;
default:
label = t("split-by-size-or-count.value.label", "Split Value");
placeholder = t("split-by-size-or-count.value.placeholder", "e.g. 10MB or 5 pages");
}
return (
<TextInput
label={label}
placeholder={placeholder}
value={parameters.splitValue}
onChange={(e) => onParameterChange('splitValue', e.target.value)}
disabled={disabled}
/>
);
};
const renderByChaptersForm = () => (
<Stack gap="sm">
<TextInput
label={t("splitByChapters.bookmarkLevel", "Bookmark Level")}
type="number"
value={parameters.bookmarkLevel}
onChange={(e) => onParameterChange('bookmarkLevel', e.target.value)}
disabled={disabled}
/>
<Checkbox
label={t("splitByChapters.includeMetadata", "Include Metadata")}
checked={parameters.includeMetadata}
onChange={(e) => onParameterChange('includeMetadata', e.currentTarget.checked)}
disabled={disabled}
/>
<Checkbox
label={t("splitByChapters.allowDuplicates", "Allow Duplicate Bookmarks")}
checked={parameters.allowDuplicates}
onChange={(e) => onParameterChange('allowDuplicates', e.currentTarget.checked)}
disabled={disabled}
/>
</Stack>
);
const renderByPageDividerForm = () => (
<Stack gap="sm">
<Anchor
href="https://stirlingpdf.io/files/Auto%20Splitter%20Divider%20(with%20instructions).pdf"
target="_blank"
size="sm"
style={{ display: 'flex', alignItems: 'center', gap: '0.5rem' }}
>
<LocalIcon icon="download-rounded" width="2rem" height="2rem" />
{t("autoSplitPDF.dividerDownload2", "Download 'Auto Splitter Divider (with instructions).pdf'")}
</Anchor>
<Checkbox
label={t("autoSplitPDF.duplexMode", "Duplex Mode (Front and back scanning)")}
checked={parameters.duplexMode}
onChange={(e) => onParameterChange('duplexMode', e.currentTarget.checked)}
disabled={disabled}
/>
</Stack>
);
// Don't render anything if no method is selected
if (!parameters.method) {
return (
<Stack gap="sm">
<Text c="dimmed" ta="center">
{t("split.settings.selectMethodFirst", "Please select a split method first")}
</Text>
</Stack>
);
}
return (
<Stack gap="md">
{/* Method-Specific Form */}
{parameters.method === SPLIT_METHODS.BY_PAGES && renderByPagesForm()}
{parameters.method === SPLIT_METHODS.BY_SECTIONS && renderBySectionsForm()}
{(parameters.method === SPLIT_METHODS.BY_SIZE ||
parameters.method === SPLIT_METHODS.BY_PAGE_COUNT ||
parameters.method === SPLIT_METHODS.BY_DOC_COUNT) && renderSplitValueForm()}
{parameters.method === SPLIT_METHODS.BY_CHAPTERS && renderByChaptersForm()}
{parameters.method === SPLIT_METHODS.BY_PAGE_DIVIDER && renderByPageDividerForm()}
</Stack>
);
};
export default SplitSettings;