Add category image upload with thumbnail backdrop in category tiles

- Add category image API methods (upload/delete) to src/api/index.js
- Add uploadCategoryImage/deleteCategoryImage thunks and extraReducers in categorySlice
- Add CategoryBackdrop component showing ThumbHash placeholder with full thumb overlay
- Add photo upload/delete tab to CategoryEditTile settings cycle
- Category tile label band uses semi-transparent black overlay with white text
- Pass thumbHash/fullHash to both CategoryTile and CategoryEditTile
This commit is contained in:
seb
2026-08-03 07:57:44 +02:00
parent 4bbe9caf55
commit 404a7f4fce
4 changed files with 257 additions and 58 deletions

View File

@@ -48,6 +48,8 @@ import {
selectChildCategories,
selectRenameMode,
patchCategoryPosterminalIds,
uploadCategoryImage,
deleteCategoryImage,
} from '../../store/categorySlice';
import {
enableTerminalCategory,
@@ -375,6 +377,33 @@ class ArtikelKategorienPage extends Component {
}}
onOpen={() => this.navigateToCategoryById(item.id)}
hasTerminals={hasTerminals}
categoryFullHash={item.fullHash}
thumbHash={item.thumbHash}
onPhotoUpload={() => {
const input = document.createElement('input');
input.type = 'file';
input.accept = 'image/*';
input.onchange = async (e) => {
const file = e.target.files?.[0];
if (!file) return;
try {
// Prepare image (resize and encode to AVIF)
const { prepareArticlePhoto } = await import('../../utils/prepareArticlePhoto');
const avifFile = await prepareArticlePhoto(file);
await this.props.uploadCategoryImage({
categoryId: item.id,
file: avifFile,
});
} catch (err) {
notifyError(err);
}
};
input.click();
}}
onPhotoDelete={() => {
void this.props.deleteCategoryImage(item.id)
.catch(notifyError);
}}
nameInput={
<TextField
value={draftName}
@@ -417,6 +446,8 @@ class ArtikelKategorienPage extends Component {
key={item.id}
label={label}
onClick={() => this.navigateToCategoryById(item.id)}
thumbHash={item.thumbHash}
fullHash={item.fullHash}
/>
);
})}
@@ -480,6 +511,8 @@ const mapDispatchToProps = {
enableTerminalCategory,
disableTerminalCategory,
patchCategoryPosterminalIds,
uploadCategoryImage,
deleteCategoryImage,
};
export default withCategoryRoute(connect(mapStateToProps, mapDispatchToProps)(ArtikelKategorienPage));