mirror of
https://github.com/arsvendg/Stirling-PDF.git
synced 2026-07-16 03:20:46 +02:00
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:
@@ -0,0 +1,13 @@
|
||||
export interface AlphabetOption {
|
||||
value: string;
|
||||
label: string;
|
||||
}
|
||||
|
||||
export const alphabetOptions: AlphabetOption[] = [
|
||||
{ value: "roman", label: "Roman" },
|
||||
{ value: "arabic", label: "العربية" },
|
||||
{ value: "japanese", label: "日本語" },
|
||||
{ value: "korean", label: "한국어" },
|
||||
{ value: "chinese", label: "简体中文" },
|
||||
{ value: "thai", label: "ไทย" },
|
||||
];
|
||||
@@ -0,0 +1,16 @@
|
||||
|
||||
// Base path from Vite config - build-time constant, normalized (no trailing slash)
|
||||
// When no subpath, use empty string instead of '.' to avoid relative path issues
|
||||
export const BASE_PATH = (import.meta.env.BASE_URL || '/').replace(/\/$/, '').replace(/^\.$/, '');
|
||||
|
||||
/** For in-app navigations when you must touch window.location (rare). */
|
||||
export const withBasePath = (path: string): string => {
|
||||
const clean = path.startsWith('/') ? path : `/${path}`;
|
||||
return `${BASE_PATH}${clean}`;
|
||||
};
|
||||
|
||||
/** For OAuth (needs absolute URL with scheme+host) */
|
||||
export const absoluteWithBasePath = (path: string): string => {
|
||||
const clean = path.startsWith('/') ? path : `/${path}`;
|
||||
return `${window.location.origin}${BASE_PATH}${clean}`;
|
||||
};
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Constants for automation functionality
|
||||
*/
|
||||
|
||||
export const AUTOMATION_CONSTANTS = {
|
||||
// Timeouts
|
||||
OPERATION_TIMEOUT: 300000, // 5 minutes in milliseconds
|
||||
|
||||
// Default values
|
||||
DEFAULT_TOOL_COUNT: 2,
|
||||
MIN_TOOL_COUNT: 2,
|
||||
|
||||
// File prefixes
|
||||
FILE_PREFIX: 'automated_',
|
||||
RESPONSE_ZIP_PREFIX: 'response_',
|
||||
RESULT_FILE_PREFIX: 'result_',
|
||||
PROCESSED_FILE_PREFIX: 'processed_',
|
||||
|
||||
// Operation types
|
||||
CONVERT_OPERATION_TYPE: 'convert',
|
||||
|
||||
// Storage keys
|
||||
DB_NAME: 'StirlingPDF_Automations',
|
||||
DB_VERSION: 1,
|
||||
STORE_NAME: 'automations',
|
||||
|
||||
// UI delays
|
||||
SPINNER_ANIMATION_DURATION: '1s'
|
||||
} as const;
|
||||
|
||||
export const AUTOMATION_STEPS = {
|
||||
SELECTION: 'selection',
|
||||
CREATION: 'creation',
|
||||
RUN: 'run'
|
||||
} as const;
|
||||
|
||||
export const EXECUTION_STATUS = {
|
||||
PENDING: 'pending',
|
||||
RUNNING: 'running',
|
||||
COMPLETED: 'completed',
|
||||
ERROR: 'error'
|
||||
} as const;
|
||||
@@ -0,0 +1,149 @@
|
||||
|
||||
export const COLOR_TYPES = {
|
||||
COLOR: 'color',
|
||||
GRAYSCALE: 'grayscale',
|
||||
BLACK_WHITE: 'blackwhite'
|
||||
} as const;
|
||||
|
||||
export const OUTPUT_OPTIONS = {
|
||||
SINGLE: 'single',
|
||||
MULTIPLE: 'multiple'
|
||||
} as const;
|
||||
|
||||
export const FIT_OPTIONS = {
|
||||
FIT_PAGE: 'fitDocumentToPage',
|
||||
MAINTAIN_ASPECT: 'maintainAspectRatio',
|
||||
FILL_PAGE: 'fillPage'
|
||||
} as const;
|
||||
|
||||
|
||||
export const CONVERSION_ENDPOINTS = {
|
||||
'office-pdf': '/api/v1/convert/file/pdf',
|
||||
'pdf-image': '/api/v1/convert/pdf/img',
|
||||
'image-pdf': '/api/v1/convert/img/pdf',
|
||||
'pdf-office-word': '/api/v1/convert/pdf/word',
|
||||
'pdf-office-presentation': '/api/v1/convert/pdf/presentation',
|
||||
'pdf-office-text': '/api/v1/convert/pdf/text',
|
||||
'pdf-csv': '/api/v1/convert/pdf/csv',
|
||||
'pdf-markdown': '/api/v1/convert/pdf/markdown',
|
||||
'pdf-html': '/api/v1/convert/pdf/html',
|
||||
'pdf-xml': '/api/v1/convert/pdf/xml',
|
||||
'pdf-pdfa': '/api/v1/convert/pdf/pdfa',
|
||||
'html-pdf': '/api/v1/convert/html/pdf',
|
||||
'markdown-pdf': '/api/v1/convert/markdown/pdf',
|
||||
'eml-pdf': '/api/v1/convert/eml/pdf'
|
||||
} as const;
|
||||
|
||||
export const ENDPOINT_NAMES = {
|
||||
'office-pdf': 'file-to-pdf',
|
||||
'pdf-image': 'pdf-to-img',
|
||||
'image-pdf': 'img-to-pdf',
|
||||
'pdf-office-word': 'pdf-to-word',
|
||||
'pdf-office-presentation': 'pdf-to-presentation',
|
||||
'pdf-office-text': 'pdf-to-text',
|
||||
'pdf-csv': 'pdf-to-csv',
|
||||
'pdf-markdown': 'pdf-to-markdown',
|
||||
'pdf-html': 'pdf-to-html',
|
||||
'pdf-xml': 'pdf-to-xml',
|
||||
'pdf-pdfa': 'pdf-to-pdfa',
|
||||
'html-pdf': 'html-to-pdf',
|
||||
'markdown-pdf': 'markdown-to-pdf',
|
||||
'eml-pdf': 'eml-to-pdf'
|
||||
} as const;
|
||||
|
||||
|
||||
// Grouped file extensions for dropdowns
|
||||
export const FROM_FORMAT_OPTIONS = [
|
||||
{ value: 'any', label: 'Any', group: 'Multiple Files' },
|
||||
{ value: 'image', label: 'Images', group: 'Multiple Files' },
|
||||
{ value: 'pdf', label: 'PDF', group: 'Document' },
|
||||
{ value: 'docx', label: 'DOCX', group: 'Document' },
|
||||
{ value: 'doc', label: 'DOC', group: 'Document' },
|
||||
{ value: 'odt', label: 'ODT', group: 'Document' },
|
||||
{ value: 'xlsx', label: 'XLSX', group: 'Spreadsheet' },
|
||||
{ value: 'xls', label: 'XLS', group: 'Spreadsheet' },
|
||||
{ value: 'ods', label: 'ODS', group: 'Spreadsheet' },
|
||||
{ value: 'pptx', label: 'PPTX', group: 'Presentation' },
|
||||
{ value: 'ppt', label: 'PPT', group: 'Presentation' },
|
||||
{ value: 'odp', label: 'ODP', group: 'Presentation' },
|
||||
{ value: 'jpg', label: 'JPG', group: 'Image' },
|
||||
{ value: 'jpeg', label: 'JPEG', group: 'Image' },
|
||||
{ value: 'png', label: 'PNG', group: 'Image' },
|
||||
{ value: 'gif', label: 'GIF', group: 'Image' },
|
||||
{ value: 'bmp', label: 'BMP', group: 'Image' },
|
||||
{ value: 'tiff', label: 'TIFF', group: 'Image' },
|
||||
{ value: 'webp', label: 'WEBP', group: 'Image' },
|
||||
{ value: 'svg', label: 'SVG', group: 'Image' },
|
||||
{ value: 'html', label: 'HTML', group: 'Web' },
|
||||
{ value: 'zip', label: 'ZIP', group: 'Web' },
|
||||
{ value: 'md', label: 'MD', group: 'Text' },
|
||||
{ value: 'txt', label: 'TXT', group: 'Text' },
|
||||
{ value: 'rtf', label: 'RTF', group: 'Text' },
|
||||
{ value: 'eml', label: 'EML', group: 'Email' },
|
||||
];
|
||||
|
||||
export const TO_FORMAT_OPTIONS = [
|
||||
{ value: 'pdf', label: 'PDF', group: 'Document' },
|
||||
{ value: 'pdfa', label: 'PDF/A', group: 'Document' },
|
||||
{ value: 'docx', label: 'DOCX', group: 'Document' },
|
||||
{ value: 'odt', label: 'ODT', group: 'Document' },
|
||||
{ value: 'csv', label: 'CSV', group: 'Spreadsheet' },
|
||||
{ value: 'pptx', label: 'PPTX', group: 'Presentation' },
|
||||
{ value: 'odp', label: 'ODP', group: 'Presentation' },
|
||||
{ value: 'txt', label: 'TXT', group: 'Text' },
|
||||
{ value: 'rtf', label: 'RTF', group: 'Text' },
|
||||
{ value: 'md', label: 'MD', group: 'Text' },
|
||||
{ value: 'png', label: 'PNG', group: 'Image' },
|
||||
{ value: 'jpg', label: 'JPG', group: 'Image' },
|
||||
{ value: 'gif', label: 'GIF', group: 'Image' },
|
||||
{ value: 'tiff', label: 'TIFF', group: 'Image' },
|
||||
{ value: 'bmp', label: 'BMP', group: 'Image' },
|
||||
{ value: 'webp', label: 'WEBP', group: 'Image' },
|
||||
{ value: 'html', label: 'HTML', group: 'Web' },
|
||||
{ value: 'xml', label: 'XML', group: 'Web' },
|
||||
];
|
||||
|
||||
// Conversion matrix - what each source format can convert to
|
||||
export const CONVERSION_MATRIX: Record<string, string[]> = {
|
||||
'any': ['pdf'], // Mixed files always convert to PDF
|
||||
'image': ['pdf'], // Multiple images always convert to PDF
|
||||
'pdf': ['png', 'jpg', 'gif', 'tiff', 'bmp', 'webp', 'docx', 'odt', 'pptx', 'odp', 'csv', 'txt', 'rtf', 'md', 'html', 'xml', 'pdfa'],
|
||||
'docx': ['pdf'], 'doc': ['pdf'], 'odt': ['pdf'],
|
||||
'xlsx': ['pdf'], 'xls': ['pdf'], 'ods': ['pdf'],
|
||||
'pptx': ['pdf'], 'ppt': ['pdf'], 'odp': ['pdf'],
|
||||
'jpg': ['pdf'], 'jpeg': ['pdf'], 'png': ['pdf'], 'gif': ['pdf'], 'bmp': ['pdf'], 'tiff': ['pdf'], 'webp': ['pdf'], 'svg': ['pdf'],
|
||||
'html': ['pdf'],
|
||||
'zip': ['pdf'],
|
||||
'md': ['pdf'],
|
||||
'txt': ['pdf'], 'rtf': ['pdf'],
|
||||
'eml': ['pdf']
|
||||
};
|
||||
|
||||
// Map extensions to endpoint keys
|
||||
export const EXTENSION_TO_ENDPOINT: Record<string, Record<string, string>> = {
|
||||
'any': { 'pdf': 'file-to-pdf' }, // Mixed files use file-to-pdf endpoint
|
||||
'image': { 'pdf': 'img-to-pdf' }, // Multiple images use img-to-pdf endpoint
|
||||
'pdf': {
|
||||
'png': 'pdf-to-img', 'jpg': 'pdf-to-img', 'gif': 'pdf-to-img', 'tiff': 'pdf-to-img', 'bmp': 'pdf-to-img', 'webp': 'pdf-to-img',
|
||||
'docx': 'pdf-to-word', 'odt': 'pdf-to-word',
|
||||
'pptx': 'pdf-to-presentation', 'odp': 'pdf-to-presentation',
|
||||
'csv': 'pdf-to-csv',
|
||||
'txt': 'pdf-to-text', 'rtf': 'pdf-to-text', 'md': 'pdf-to-markdown',
|
||||
'html': 'pdf-to-html', 'xml': 'pdf-to-xml',
|
||||
'pdfa': 'pdf-to-pdfa'
|
||||
},
|
||||
'docx': { 'pdf': 'file-to-pdf' }, 'doc': { 'pdf': 'file-to-pdf' }, 'odt': { 'pdf': 'file-to-pdf' },
|
||||
'xlsx': { 'pdf': 'file-to-pdf' }, 'xls': { 'pdf': 'file-to-pdf' }, 'ods': { 'pdf': 'file-to-pdf' },
|
||||
'pptx': { 'pdf': 'file-to-pdf' }, 'ppt': { 'pdf': 'file-to-pdf' }, 'odp': { 'pdf': 'file-to-pdf' },
|
||||
'jpg': { 'pdf': 'img-to-pdf' }, 'jpeg': { 'pdf': 'img-to-pdf' }, 'png': { 'pdf': 'img-to-pdf' },
|
||||
'gif': { 'pdf': 'img-to-pdf' }, 'bmp': { 'pdf': 'img-to-pdf' }, 'tiff': { 'pdf': 'img-to-pdf' }, 'webp': { 'pdf': 'img-to-pdf' }, 'svg': { 'pdf': 'img-to-pdf' },
|
||||
'html': { 'pdf': 'html-to-pdf' },
|
||||
'zip': { 'pdf': 'html-to-pdf' },
|
||||
'md': { 'pdf': 'markdown-to-pdf' },
|
||||
'txt': { 'pdf': 'file-to-pdf' }, 'rtf': { 'pdf': 'file-to-pdf' },
|
||||
'eml': { 'pdf': 'eml-to-pdf' }
|
||||
};
|
||||
|
||||
export type ColorType = typeof COLOR_TYPES[keyof typeof COLOR_TYPES];
|
||||
export type OutputOption = typeof OUTPUT_OPTIONS[keyof typeof OUTPUT_OPTIONS];
|
||||
export type FitOption = typeof FIT_OPTIONS[keyof typeof FIT_OPTIONS];
|
||||
@@ -0,0 +1,21 @@
|
||||
// Central list of formats supported by Convert operations
|
||||
export const CONVERT_SUPPORTED_FORMATS = [
|
||||
// Microsoft Office
|
||||
'doc', 'docx', 'dot', 'dotx', 'csv', 'xls', 'xlsx', 'xlt', 'xltx', 'slk', 'dif', 'ppt', 'pptx',
|
||||
// OpenDocument
|
||||
'odt', 'ott', 'ods', 'ots', 'odp', 'otp', 'odg', 'otg',
|
||||
// Text formats
|
||||
'txt', 'text', 'xml', 'rtf', 'html', 'lwp', 'md',
|
||||
// Images
|
||||
'bmp', 'gif', 'jpeg', 'jpg', 'png', 'tif', 'tiff', 'pbm', 'pgm', 'ppm', 'ras', 'xbm', 'xpm', 'svg', 'svm', 'wmf', 'webp',
|
||||
// StarOffice
|
||||
'sda', 'sdc', 'sdd', 'sdw', 'stc', 'std', 'sti', 'stw', 'sxd', 'sxg', 'sxi', 'sxw',
|
||||
// Email formats
|
||||
'eml',
|
||||
// Archive formats
|
||||
'zip',
|
||||
// Other
|
||||
'dbf', 'fods', 'vsd', 'vor', 'vor3', 'vor4', 'uop', 'pct', 'ps', 'pdf',
|
||||
];
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
import { PAGE_SIZES } from "@app/constants/pageSizeConstants";
|
||||
|
||||
// Default crop area (covers entire page)
|
||||
export const DEFAULT_CROP_AREA = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: PAGE_SIZES.A4.width,
|
||||
height: PAGE_SIZES.A4.height,
|
||||
} as const;
|
||||
|
||||
|
||||
export type ResizeHandle = 'nw' | 'ne' | 'sw' | 'se' | 'n' | 'e' | 's' | 'w' | null;
|
||||
@@ -0,0 +1,8 @@
|
||||
// Default PDF page sizes in points (1 point = 1/72 inch)
|
||||
export const PAGE_SIZES = {
|
||||
A4: { width: 595, height: 842 },
|
||||
LETTER: { width: 612, height: 792 },
|
||||
A3: { width: 842, height: 1191 },
|
||||
A5: { width: 420, height: 595 },
|
||||
LEGAL: { width: 612, height: 1008 },
|
||||
} as const;
|
||||
@@ -0,0 +1,78 @@
|
||||
export const SPLIT_METHODS = {
|
||||
BY_PAGES: 'byPages',
|
||||
BY_SECTIONS: 'bySections',
|
||||
BY_SIZE: 'bySize',
|
||||
BY_PAGE_COUNT: 'byPageCount',
|
||||
BY_DOC_COUNT: 'byDocCount',
|
||||
BY_CHAPTERS: 'byChapters',
|
||||
BY_PAGE_DIVIDER: 'byPageDivider'
|
||||
} as const;
|
||||
|
||||
|
||||
export const ENDPOINTS = {
|
||||
[SPLIT_METHODS.BY_PAGES]: 'split-pages',
|
||||
[SPLIT_METHODS.BY_SECTIONS]: 'split-pdf-by-sections',
|
||||
[SPLIT_METHODS.BY_SIZE]: 'split-by-size-or-count',
|
||||
[SPLIT_METHODS.BY_PAGE_COUNT]: 'split-by-size-or-count',
|
||||
[SPLIT_METHODS.BY_DOC_COUNT]: 'split-by-size-or-count',
|
||||
[SPLIT_METHODS.BY_CHAPTERS]: 'split-pdf-by-chapters',
|
||||
[SPLIT_METHODS.BY_PAGE_DIVIDER]: 'auto-split-pdf'
|
||||
} as const;
|
||||
|
||||
export type SplitMethod = typeof SPLIT_METHODS[keyof typeof SPLIT_METHODS];
|
||||
export const isSplitMethod = (value: string | null): value is SplitMethod => {
|
||||
return Object.values(SPLIT_METHODS).includes(value as SplitMethod);
|
||||
};
|
||||
|
||||
import { CardOption } from '@app/components/shared/CardSelector';
|
||||
|
||||
export interface MethodOption extends CardOption<SplitMethod> {
|
||||
tooltipKey: string;
|
||||
}
|
||||
|
||||
export const METHOD_OPTIONS: MethodOption[] = [
|
||||
{
|
||||
value: SPLIT_METHODS.BY_PAGES,
|
||||
prefixKey: "split.methods.prefix.splitAt",
|
||||
nameKey: "split.methods.byPages.name",
|
||||
tooltipKey: "split.methods.byPages.tooltip"
|
||||
},
|
||||
{
|
||||
value: SPLIT_METHODS.BY_CHAPTERS,
|
||||
prefixKey: "split.methods.prefix.splitBy",
|
||||
nameKey: "split.methods.byChapters.name",
|
||||
tooltipKey: "split.methods.byChapters.tooltip"
|
||||
},
|
||||
{
|
||||
value: SPLIT_METHODS.BY_SECTIONS,
|
||||
prefixKey: "split.methods.prefix.splitBy",
|
||||
nameKey: "split.methods.bySections.name",
|
||||
tooltipKey: "split.methods.bySections.tooltip"
|
||||
},
|
||||
{
|
||||
value: SPLIT_METHODS.BY_SIZE,
|
||||
prefixKey: "split.methods.prefix.splitBy",
|
||||
nameKey: "split.methods.bySize.name",
|
||||
tooltipKey: "split.methods.bySize.tooltip"
|
||||
},
|
||||
{
|
||||
value: SPLIT_METHODS.BY_PAGE_COUNT,
|
||||
prefixKey: "split.methods.prefix.splitBy",
|
||||
nameKey: "split.methods.byPageCount.name",
|
||||
tooltipKey: "split.methods.byPageCount.tooltip"
|
||||
},
|
||||
{
|
||||
value: SPLIT_METHODS.BY_DOC_COUNT,
|
||||
prefixKey: "split.methods.prefix.splitBy",
|
||||
nameKey: "split.methods.byDocCount.name",
|
||||
tooltipKey: "split.methods.byDocCount.tooltip"
|
||||
},
|
||||
{
|
||||
value: SPLIT_METHODS.BY_PAGE_DIVIDER,
|
||||
prefixKey: "split.methods.prefix.splitBy",
|
||||
nameKey: "split.methods.byPageDivider.name",
|
||||
tooltipKey: "split.methods.byPageDivider.tooltip"
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
// Theme constants and utilities
|
||||
|
||||
export type ThemeMode = 'light' | 'dark' | 'rainbow';
|
||||
|
||||
// Detect OS theme preference
|
||||
export function getSystemTheme(): 'light' | 'dark' {
|
||||
return window?.matchMedia?.('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
// Tool panel constants
|
||||
|
||||
export type ToolPanelMode = 'sidebar' | 'fullscreen';
|
||||
|
||||
export const DEFAULT_TOOL_PANEL_MODE: ToolPanelMode = 'sidebar';
|
||||
Reference in New Issue
Block a user