Feature/v2/landing page upload buttons (#4259)

# Description of Changes

<img width="659" height="453" alt="Screenshot 2025-08-22 at 5 28 53 PM"
src="https://github.com/user-attachments/assets/1dd0f63c-0b08-435c-bb0e-00bd85be7f24"
/>
<img width="968" height="766" alt="Screenshot 2025-08-22 at 5 30 00 PM"
src="https://github.com/user-attachments/assets/86614256-1375-4e6e-b5bb-ae9cb6708135"
/>

---

## Checklist

### General

- [ ] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [ ] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [ ] I have performed a self-review of my own code
- [ ] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
This commit is contained in:
EthanHealy01 2025-08-25 12:43:20 +01:00 committed by GitHub
parent 888bac9408
commit 61f5221c58
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 79 additions and 17 deletions

View File

@ -604,6 +604,10 @@
"desc": "Build multi-step workflows by chaining together PDF actions. Ideal for recurring tasks." "desc": "Build multi-step workflows by chaining together PDF actions. Ideal for recurring tasks."
} }
}, },
"landing": {
"addFiles": "Add Files",
"uploadFromComputer": "Upload from computer"
},
"viewPdf": { "viewPdf": {
"tags": "view,read,annotate,text,image,highlight,edit", "tags": "view,read,annotate,text,image,highlight,edit",
"title": "View/Edit PDF", "title": "View/Edit PDF",

View File

@ -607,6 +607,10 @@
"desc": "Replace color for text and background in PDF and invert full color of pdf to reduce file size" "desc": "Replace color for text and background in PDF and invert full color of pdf to reduce file size"
} }
}, },
"landing": {
"addFiles": "Add Files",
"uploadFromComputer": "Upload from computer"
},
"viewPdf": { "viewPdf": {
"tags": "view,read,annotate,text,image,highlight,edit", "tags": "view,read,annotate,text,image,highlight,edit",
"title": "View/Edit PDF", "title": "View/Edit PDF",

View File

@ -4,18 +4,25 @@ import { Dropzone } from '@mantine/dropzone';
import AddIcon from '@mui/icons-material/Add'; import AddIcon from '@mui/icons-material/Add';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useFileHandler } from '../../hooks/useFileHandler'; import { useFileHandler } from '../../hooks/useFileHandler';
import { useFilesModalContext } from '../../contexts/FilesModalContext';
const LandingPage = () => { const LandingPage = () => {
const { addMultipleFiles } = useFileHandler(); const { addMultipleFiles } = useFileHandler();
const fileInputRef = React.useRef<HTMLInputElement>(null); const fileInputRef = React.useRef<HTMLInputElement>(null);
const { colorScheme } = useMantineColorScheme(); const { colorScheme } = useMantineColorScheme();
const { t } = useTranslation(); const { t } = useTranslation();
const { openFilesModal } = useFilesModalContext();
const [isUploadHover, setIsUploadHover] = React.useState(false);
const handleFileDrop = async (files: File[]) => { const handleFileDrop = async (files: File[]) => {
await addMultipleFiles(files); await addMultipleFiles(files);
}; };
const handleAddFilesClick = () => { const handleOpenFilesModal = () => {
openFilesModal();
};
const handleNativeUploadClick = () => {
fileInputRef.current?.click(); fileInputRef.current?.click();
}; };
@ -44,7 +51,7 @@ const LandingPage = () => {
borderRadius: '0.5rem 0.5rem 0 0', borderRadius: '0.5rem 0.5rem 0 0',
filter: 'var(--drop-shadow-filter)', filter: 'var(--drop-shadow-filter)',
backgroundColor: 'var(--landing-paper-bg)', backgroundColor: 'var(--landing-paper-bg)',
transition: 'background-color 0.2s ease', transition: 'background-color 0.4s ease',
}} }}
activateOnClick={false} activateOnClick={false}
styles={{ styles={{
@ -99,26 +106,73 @@ const LandingPage = () => {
/> />
</Group> </Group>
{/* Add Files Button */} {/* Add Files + Native Upload Buttons */}
<Button <div
style={{ style={{
backgroundColor: 'var(--landing-button-bg)', display: 'flex',
color: 'var(--landing-button-color)', alignItems: 'center',
border: '1px solid var(--landing-button-border)', justifyContent: 'center',
borderRadius: '2rem', gap: '0.6rem',
height: '38px',
width: '80%', width: '80%',
marginTop: '0.8rem', marginTop: '0.8rem',
marginBottom: '0.8rem', marginBottom: '0.8rem'
}} }}
onClick={handleAddFilesClick} onMouseLeave={() => setIsUploadHover(false)}
> >
<AddIcon className="text-[var(--accent-interactive)]" /> <Button
<span> style={{
{t('fileUpload.uploadFiles', 'Upload Files')} backgroundColor: 'var(--landing-button-bg)',
</span> color: 'var(--landing-button-color)',
</Button> border: '1px solid var(--landing-button-border)',
borderRadius: '2rem',
height: '38px',
paddingLeft: isUploadHover ? 0 : '1rem',
paddingRight: isUploadHover ? 0 : '1rem',
width: isUploadHover ? '58px' : 'calc(100% - 58px - 0.6rem)',
minWidth: isUploadHover ? '58px' : undefined,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
transition: 'width .5s ease, padding .5s ease'
}}
onClick={handleOpenFilesModal}
onMouseEnter={() => setIsUploadHover(false)}
>
<AddIcon className="text-[var(--accent-interactive)]" />
{!isUploadHover && (
<span>
{t('landing.addFiles', 'Add Files')}
</span>
)}
</Button>
<Button
aria-label="Upload"
style={{
backgroundColor: 'var(--landing-button-bg)',
color: 'var(--landing-button-color)',
border: '1px solid var(--landing-button-border)',
borderRadius: '1rem',
height: '38px',
width: isUploadHover ? 'calc(100% - 50px)' : '58px',
minWidth: '58px',
paddingLeft: isUploadHover ? '1rem' : 0,
paddingRight: isUploadHover ? '1rem' : 0,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
transition: 'width .5s ease, padding .5s ease'
}}
onClick={handleNativeUploadClick}
onMouseEnter={() => setIsUploadHover(true)}
>
<span className="material-symbols-rounded" style={{ fontSize: '1.25rem', color: 'var(--accent-interactive)' }}>upload</span>
{isUploadHover && (
<span style={{ marginLeft: '.5rem' }}>
{t('landing.uploadFromComputer', 'Upload from computer')}
</span>
)}
</Button>
</div>
{/* Hidden file input for native file picker */} {/* Hidden file input for native file picker */}
<input <input