This commit is contained in:
23
src/components/CalculatorMode.jsx
Normal file
23
src/components/CalculatorMode.jsx
Normal file
@@ -0,0 +1,23 @@
|
||||
import { Select } from 'antd';
|
||||
|
||||
export default function CalculatorMode({ value, onChange }) {
|
||||
return (
|
||||
<div className="form-row">
|
||||
<label htmlFor="calculator-mode" className="form-label">
|
||||
Calculate
|
||||
</label>
|
||||
<Select
|
||||
id="calculator-mode"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
size="large"
|
||||
style={{ width: '100%' }}
|
||||
options={[
|
||||
{ value: 'shooting-interval', label: 'Shooting interval' },
|
||||
{ value: 'clip-length', label: 'Clip length' },
|
||||
{ value: 'event-duration', label: 'Event duration' },
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
9
src/components/Header.jsx
Normal file
9
src/components/Header.jsx
Normal file
@@ -0,0 +1,9 @@
|
||||
export default function Header() {
|
||||
return (
|
||||
<header className="header">
|
||||
<div className="container">
|
||||
<h1>TIMELAPSE CALCULATOR</h1>
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
}
|
||||
25
src/components/NumberInput.jsx
Normal file
25
src/components/NumberInput.jsx
Normal file
@@ -0,0 +1,25 @@
|
||||
import { InputNumber } from 'antd';
|
||||
|
||||
export default function NumberInput({ label, value, onChange, unit, min = 0, step = 1 }) {
|
||||
const handleChange = (newValue) => {
|
||||
const numValue = Math.max(min, newValue || 0);
|
||||
onChange(numValue);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="form-row">
|
||||
<label className="form-label">{label}</label>
|
||||
<InputNumber
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
min={min}
|
||||
step={step}
|
||||
placeholder="0"
|
||||
addonAfter={unit}
|
||||
size="large"
|
||||
style={{ width: '100%' }}
|
||||
controls={false}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
54
src/components/Results.jsx
Normal file
54
src/components/Results.jsx
Normal file
@@ -0,0 +1,54 @@
|
||||
import { Statistic, Row, Col } from 'antd';
|
||||
|
||||
export default function Results({ shootingInterval, numberOfPhotos, totalMemory }) {
|
||||
const formatTime = (seconds) => {
|
||||
if (seconds < 60) {
|
||||
return `${seconds.toFixed(0)}s`;
|
||||
} else if (seconds < 3600) {
|
||||
const mins = Math.floor(seconds / 60);
|
||||
const secs = Math.floor(seconds % 60);
|
||||
return `${mins}m ${secs}s`;
|
||||
} else {
|
||||
const hours = Math.floor(seconds / 3600);
|
||||
const mins = Math.floor((seconds % 3600) / 60);
|
||||
const secs = Math.floor(seconds % 60);
|
||||
return `${hours}h ${mins}m ${secs}s`;
|
||||
}
|
||||
};
|
||||
|
||||
const formatMemory = (mb) => {
|
||||
if (mb < 1024) {
|
||||
return `${mb.toFixed(2)}MB`;
|
||||
} else {
|
||||
return `${(mb / 1024).toFixed(2)}GB`;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="results-section">
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col xs={24} sm={8}>
|
||||
<Statistic
|
||||
title="Shooting interval"
|
||||
value={formatTime(shootingInterval)}
|
||||
valueStyle={{ color: '#2C3E50', fontSize: '1.5rem', fontWeight: 600 }}
|
||||
/>
|
||||
</Col>
|
||||
<Col xs={24} sm={8}>
|
||||
<Statistic
|
||||
title="Number of photos"
|
||||
value={numberOfPhotos}
|
||||
valueStyle={{ color: '#2C3E50', fontSize: '1.5rem', fontWeight: 600 }}
|
||||
/>
|
||||
</Col>
|
||||
<Col xs={24} sm={8}>
|
||||
<Statistic
|
||||
title="Total memory usage"
|
||||
value={formatMemory(totalMemory)}
|
||||
valueStyle={{ color: '#2C3E50', fontSize: '1.5rem', fontWeight: 600 }}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
53
src/components/TimeInput.jsx
Normal file
53
src/components/TimeInput.jsx
Normal file
@@ -0,0 +1,53 @@
|
||||
import { InputNumber, Space } from 'antd';
|
||||
|
||||
export default function TimeInput({ label, hours, minutes, seconds, onChange }) {
|
||||
const handleChange = (field, value) => {
|
||||
// Ensure non-negative values
|
||||
const numValue = Math.max(0, value || 0);
|
||||
onChange({
|
||||
hours: field === 'hours' ? numValue : hours,
|
||||
minutes: field === 'minutes' ? numValue : minutes,
|
||||
seconds: field === 'seconds' ? numValue : seconds,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="form-row">
|
||||
<label className="form-label">{label}</label>
|
||||
<Space.Compact style={{ width: '100%' }} size="large">
|
||||
<InputNumber
|
||||
value={hours}
|
||||
onChange={(value) => handleChange('hours', value)}
|
||||
min={0}
|
||||
placeholder="0"
|
||||
addonAfter="h"
|
||||
size="large"
|
||||
style={{ width: '33.33%' }}
|
||||
controls={false}
|
||||
/>
|
||||
<InputNumber
|
||||
value={minutes}
|
||||
onChange={(value) => handleChange('minutes', value)}
|
||||
min={0}
|
||||
max={59}
|
||||
placeholder="0"
|
||||
addonAfter="m"
|
||||
size="large"
|
||||
style={{ width: '33.33%' }}
|
||||
controls={false}
|
||||
/>
|
||||
<InputNumber
|
||||
value={seconds}
|
||||
onChange={(value) => handleChange('seconds', value)}
|
||||
min={0}
|
||||
max={59}
|
||||
placeholder="0"
|
||||
addonAfter="s"
|
||||
size="large"
|
||||
style={{ width: '33.34%' }}
|
||||
controls={false}
|
||||
/>
|
||||
</Space.Compact>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user