Change Cart disposition
This commit is contained in:
2
.github/workflows/node.js.yml
vendored
2
.github/workflows/node.js.yml
vendored
@@ -33,7 +33,7 @@ jobs:
|
|||||||
run: npm run build --if-present
|
run: npm run build --if-present
|
||||||
env:
|
env:
|
||||||
CI: false
|
CI: false
|
||||||
REACT_APP_APIUrl: ${{ secrets.REACT_APP_APIUrl }}
|
REACT_APP_API_URL: ${{ secrets.REACT_APP_API_URL }}
|
||||||
|
|
||||||
- run: npm test -- --passWithNoTests
|
- run: npm test -- --passWithNoTests
|
||||||
|
|
||||||
|
|||||||
9
package-lock.json
generated
9
package-lock.json
generated
@@ -19,6 +19,7 @@
|
|||||||
"@testing-library/react": "^13.4.0",
|
"@testing-library/react": "^13.4.0",
|
||||||
"@testing-library/user-event": "^13.5.0",
|
"@testing-library/user-event": "^13.5.0",
|
||||||
"axios": "^1.7.6",
|
"axios": "^1.7.6",
|
||||||
|
"lucide-react": "^0.453.0",
|
||||||
"material-ui-dropzone": "^3.5.0",
|
"material-ui-dropzone": "^3.5.0",
|
||||||
"query-string": "^9.1.0",
|
"query-string": "^9.1.0",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
@@ -14800,6 +14801,14 @@
|
|||||||
"yallist": "^3.0.2"
|
"yallist": "^3.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/lucide-react": {
|
||||||
|
"version": "0.453.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.453.0.tgz",
|
||||||
|
"integrity": "sha512-kL+RGZCcJi9BvJtzg2kshO192Ddy9hv3ij+cPrVPWSRzgCWCVazoQJxOjAwgK53NomL07HB7GPHW120FimjNhQ==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/lz-string": {
|
"node_modules/lz-string": {
|
||||||
"version": "1.5.0",
|
"version": "1.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz",
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
"@testing-library/react": "^13.4.0",
|
"@testing-library/react": "^13.4.0",
|
||||||
"@testing-library/user-event": "^13.5.0",
|
"@testing-library/user-event": "^13.5.0",
|
||||||
"axios": "^1.7.6",
|
"axios": "^1.7.6",
|
||||||
|
"lucide-react": "^0.453.0",
|
||||||
"material-ui-dropzone": "^3.5.0",
|
"material-ui-dropzone": "^3.5.0",
|
||||||
"query-string": "^9.1.0",
|
"query-string": "^9.1.0",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
|
|||||||
@@ -1,27 +1,9 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from 'react';
|
||||||
import { useSelector, useDispatch } from "react-redux";
|
import { useSelector, useDispatch } from 'react-redux';
|
||||||
import {
|
import { removePoster } from '../services/action';
|
||||||
Container,
|
import DeleteIcon from '@material-ui/icons/Delete';
|
||||||
Typography,
|
|
||||||
Card,
|
const apiUrl = process.env.REACT_APP_API_URL;
|
||||||
CardMedia,
|
|
||||||
CardContent,
|
|
||||||
Button,
|
|
||||||
Checkbox,
|
|
||||||
FormControlLabel,
|
|
||||||
TextField,
|
|
||||||
Dialog,
|
|
||||||
DialogTitle,
|
|
||||||
DialogContent,
|
|
||||||
DialogActions,
|
|
||||||
Paper,
|
|
||||||
} from "@material-ui/core";
|
|
||||||
import DeleteIcon from "@material-ui/icons/Delete";
|
|
||||||
import GetAppIcon from "@material-ui/icons/GetApp";
|
|
||||||
import ShareIcon from "@material-ui/icons/Share";
|
|
||||||
import EditIcon from "@material-ui/icons/Edit";
|
|
||||||
import { removePoster } from "../services/action";
|
|
||||||
import axios from "axios";
|
|
||||||
|
|
||||||
const Cart = () => {
|
const Cart = () => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
@@ -32,192 +14,88 @@ const Cart = () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const [selectedForDownload, setSelectedForDownload] = useState(
|
const [downloadFormat, setDownloadFormat] = useState('zip');
|
||||||
selectedPosters.map(() => true)
|
|
||||||
);
|
|
||||||
const [downloadFormat, setDownloadFormat] = useState("zip");
|
|
||||||
const [renameDialogOpen, setRenameDialogOpen] = useState(false);
|
|
||||||
const [currentPosterIndex, setCurrentPosterIndex] = useState(null);
|
|
||||||
const [newPosterName, setNewPosterName] = useState("");
|
|
||||||
|
|
||||||
const handleRemovePoster = (index) => {
|
const handleRemovePoster = (movieId, posterId) => {
|
||||||
dispatch(
|
dispatch(removePoster(movieId, posterId));
|
||||||
removePoster(
|
|
||||||
selectedPosters[index].movieId,
|
|
||||||
selectedPosters[index].posterId
|
|
||||||
)
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDownload = async () => {
|
const handleDownload = async () => {
|
||||||
const postersToDownload = selectedPosters
|
|
||||||
.filter((_, index) => selectedForDownload[index])
|
|
||||||
.map((poster) => ({
|
|
||||||
movieId: poster.movieId,
|
|
||||||
posterId: poster.posterId,
|
|
||||||
movieName: poster.movieName,
|
|
||||||
movieYear: poster.movieYear,
|
|
||||||
}));
|
|
||||||
|
|
||||||
console.log("Downloading posters:", postersToDownload);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await axios.post(
|
const response = await fetch(`${apiUrl}/api/download-posters`, {
|
||||||
"http://localhost:5000/api/download-posters",
|
method: 'POST',
|
||||||
{
|
headers: {
|
||||||
posters: postersToDownload,
|
'Content-Type': 'application/json',
|
||||||
format: downloadFormat,
|
|
||||||
},
|
},
|
||||||
{
|
body: JSON.stringify({
|
||||||
responseType: "blob",
|
posters: selectedPosters,
|
||||||
}
|
format: downloadFormat,
|
||||||
);
|
}),
|
||||||
|
|
||||||
const blob = new Blob([response.data], {
|
|
||||||
type: response.headers["content-type"],
|
|
||||||
});
|
});
|
||||||
const link = document.createElement("a");
|
|
||||||
link.href = window.URL.createObjectURL(blob);
|
if (!response.ok) throw new Error('Download failed');
|
||||||
link.download = `posters.${downloadFormat}`;
|
|
||||||
|
const contentType = response.headers.get('content-type');
|
||||||
|
if (contentType && contentType.includes('application/zip')) {
|
||||||
|
const blob = await response.blob();
|
||||||
|
const url = window.URL.createObjectURL(blob);
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = url;
|
||||||
|
link.download = 'posters.zip';
|
||||||
|
document.body.appendChild(link);
|
||||||
link.click();
|
link.click();
|
||||||
} catch (error) {
|
link.remove();
|
||||||
console.error("Failed to download posters:", error);
|
window.URL.revokeObjectURL(url);
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid response format');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to download posters:', error);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
const handleShare = () => {
|
|
||||||
console.log("Sharing selected posters");
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleRename = (index) => {
|
|
||||||
setCurrentPosterIndex(index);
|
|
||||||
setNewPosterName(selectedPosters[index].posterId);
|
|
||||||
setRenameDialogOpen(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleRenameConfirm = () => {
|
|
||||||
console.log(`Renaming poster ${currentPosterIndex} to ${newPosterName}`);
|
|
||||||
setRenameDialogOpen(false);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container className="cart-container">
|
<div className="cart-container">
|
||||||
<div className="poster-list">
|
<div className="poster-grid">
|
||||||
<Typography variant="h4" gutterBottom className="cart-title">
|
{selectedPosters.map((poster) => (
|
||||||
Your Cart
|
<div key={`${poster.movieId}-${poster.posterId}`} className="poster-card">
|
||||||
</Typography>
|
<img
|
||||||
{selectedPosters.map((poster, index) => (
|
src={`https://image.tmdb.org/t/p/w500${poster.posterId}`}
|
||||||
<Card key={index} className="poster-card">
|
alt="Movie poster"
|
||||||
<CardMedia
|
className="poster-image"
|
||||||
className="poster-media"
|
|
||||||
image={`https://image.tmdb.org/t/p/w500${poster.posterId}`}
|
|
||||||
title={`Poster ${index + 1}`}
|
|
||||||
/>
|
/>
|
||||||
<CardContent className="poster-content">
|
<div className="delete-overlay">
|
||||||
<Typography variant="h6" className="poster-title">
|
<button
|
||||||
{`Movie ID: ${poster.movieId}`}
|
className="delete-button"
|
||||||
</Typography>
|
onClick={() => handleRemovePoster(poster.movieId, poster.posterId)}
|
||||||
<Typography variant="body2" className="poster-id">
|
|
||||||
{poster.posterId}
|
|
||||||
</Typography>
|
|
||||||
<FormControlLabel
|
|
||||||
control={
|
|
||||||
<Checkbox
|
|
||||||
checked={selectedForDownload[index]}
|
|
||||||
onChange={(e) => {
|
|
||||||
const newSelected = [...selectedForDownload];
|
|
||||||
newSelected[index] = e.target.checked;
|
|
||||||
setSelectedForDownload(newSelected);
|
|
||||||
}}
|
|
||||||
className="checkbox"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
label="Select for download"
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
startIcon={<DeleteIcon />}
|
|
||||||
onClick={() => handleRemovePoster(index)}
|
|
||||||
className="action-button"
|
|
||||||
>
|
>
|
||||||
Remove
|
<DeleteIcon />
|
||||||
</Button>
|
</button>
|
||||||
<Button
|
</div>
|
||||||
startIcon={<EditIcon />}
|
</div>
|
||||||
onClick={() => handleRename(index)}
|
|
||||||
className="action-button"
|
|
||||||
>
|
|
||||||
Rename
|
|
||||||
</Button>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<Paper className="action-panel" elevation={3}>
|
|
||||||
<div className="action-buttons">
|
<div className="action-panel">
|
||||||
<Typography gutterBottom className="action-title">
|
<h2>Download Options</h2>
|
||||||
Download Format
|
<select
|
||||||
</Typography>
|
|
||||||
<TextField
|
|
||||||
select
|
|
||||||
value={downloadFormat}
|
value={downloadFormat}
|
||||||
onChange={(e) => setDownloadFormat(e.target.value)}
|
onChange={(e) => setDownloadFormat(e.target.value)}
|
||||||
SelectProps={{
|
className="format-select"
|
||||||
native: true,
|
|
||||||
}}
|
|
||||||
className="form-control"
|
|
||||||
>
|
>
|
||||||
<option value="zip">ZIP</option>
|
<option value="zip">ZIP</option>
|
||||||
<option value="tar">TAR</option>
|
<option value="tar">TAR</option>
|
||||||
<option value="7z">7Z</option>
|
<option value="7z">7Z</option>
|
||||||
</TextField>
|
</select>
|
||||||
<Button
|
<button
|
||||||
variant="contained"
|
className="download-button"
|
||||||
color="primary"
|
|
||||||
startIcon={<GetAppIcon />}
|
|
||||||
onClick={handleDownload}
|
onClick={handleDownload}
|
||||||
disabled={selectedForDownload.every((selected) => !selected)}
|
disabled={selectedPosters.length === 0}
|
||||||
className="primary-button"
|
|
||||||
>
|
>
|
||||||
Download Selected
|
Download Selected
|
||||||
</Button>
|
</button>
|
||||||
<Button
|
</div>
|
||||||
variant="contained"
|
|
||||||
color="secondary"
|
|
||||||
startIcon={<ShareIcon />}
|
|
||||||
onClick={handleShare}
|
|
||||||
className="secondary-button"
|
|
||||||
>
|
|
||||||
Share Selection
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
</Paper>
|
|
||||||
<Dialog
|
|
||||||
open={renameDialogOpen}
|
|
||||||
onClose={() => setRenameDialogOpen(false)}
|
|
||||||
className="rename-dialog"
|
|
||||||
>
|
|
||||||
<DialogTitle className="dialog-title">Rename Poster</DialogTitle>
|
|
||||||
<DialogContent className="dialog-content">
|
|
||||||
<TextField
|
|
||||||
autoFocus
|
|
||||||
margin="dense"
|
|
||||||
label="New Name"
|
|
||||||
type="text"
|
|
||||||
fullWidth
|
|
||||||
value={newPosterName}
|
|
||||||
onChange={(e) => setNewPosterName(e.target.value)}
|
|
||||||
/>
|
|
||||||
</DialogContent>
|
|
||||||
<DialogActions className="dialog-actions">
|
|
||||||
<Button onClick={() => setRenameDialogOpen(false)} color="primary">
|
|
||||||
Cancel
|
|
||||||
</Button>
|
|
||||||
<Button onClick={handleRenameConfirm} color="primary">
|
|
||||||
Rename
|
|
||||||
</Button>
|
|
||||||
</DialogActions>
|
|
||||||
</Dialog>
|
|
||||||
</Container>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,34 +1,11 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
import { AppBar, Toolbar, IconButton, Badge, Button } from '@material-ui/core';
|
import { AppBar, Toolbar, IconButton, Badge, Button } from '@material-ui/core';
|
||||||
import { makeStyles } from '@material-ui/core/styles';
|
|
||||||
import ShoppingCartIcon from '@material-ui/icons/ShoppingCart';
|
import ShoppingCartIcon from '@material-ui/icons/ShoppingCart';
|
||||||
import ArrowBackIcon from '@material-ui/icons/ArrowBack';
|
import ArrowBackIcon from '@material-ui/icons/ArrowBack';
|
||||||
import { useNavigate, useLocation } from 'react-router-dom';
|
import { useNavigate, useLocation } from 'react-router-dom';
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const NavBar = ({ onRefreshFiles }) => {
|
||||||
appBar: {
|
|
||||||
top: 'auto',
|
|
||||||
bottom: 0,
|
|
||||||
backgroundColor: '#1c1f23',
|
|
||||||
},
|
|
||||||
toolbar: {
|
|
||||||
justifyContent: 'space-between',
|
|
||||||
},
|
|
||||||
backButton: {
|
|
||||||
color: 'white',
|
|
||||||
},
|
|
||||||
cartButton: {
|
|
||||||
color: 'white',
|
|
||||||
},
|
|
||||||
refreshButton: {
|
|
||||||
color: 'white',
|
|
||||||
marginRight: theme.spacing(2),
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
const NavBar = ({onRefreshFiles}) => {
|
|
||||||
const classes = useStyles();
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const selectedPosters = useSelector((state) => {
|
const selectedPosters = useSelector((state) => {
|
||||||
@@ -49,22 +26,22 @@ const NavBar = ({onRefreshFiles}) => {
|
|||||||
const isPosterSelectorPage = location.pathname !== '/PosterSelector';
|
const isPosterSelectorPage = location.pathname !== '/PosterSelector';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppBar position="fixed" className={classes.appBar}>
|
<AppBar position="fixed" className="navbar">
|
||||||
<Toolbar className={classes.toolbar}>
|
<Toolbar className="toolbar">
|
||||||
{isPosterSelectorPage ? (
|
{isPosterSelectorPage ? (
|
||||||
<IconButton edge="start" className={classes.backButton} onClick={handleBack}>
|
<IconButton edge="start" className="back-button" onClick={handleBack}>
|
||||||
<ArrowBackIcon />
|
<ArrowBackIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
) : (
|
) : (
|
||||||
<IconButton edge="start" className={classes.backButton} disabled>
|
<IconButton edge="start" className="back-button" disabled>
|
||||||
{/* Un IconButton vide et désactivé */}
|
{/* Un IconButton vide et désactivé */}
|
||||||
</IconButton>
|
</IconButton>
|
||||||
)}
|
)}
|
||||||
<div>
|
<div>
|
||||||
<Button className={classes.refreshButton} onClick={onRefreshFiles}>
|
<Button className="refresh-button" onClick={onRefreshFiles}>
|
||||||
Refresh Files
|
Refresh Files
|
||||||
</Button>
|
</Button>
|
||||||
<IconButton edge="end" className={classes.cartButton} onClick={handleCart}>
|
<IconButton edge="end" className="cart-button" onClick={handleCart}>
|
||||||
<Badge badgeContent={totalSelected} color="secondary">
|
<Badge badgeContent={totalSelected} color="secondary">
|
||||||
<ShoppingCartIcon />
|
<ShoppingCartIcon />
|
||||||
</Badge>
|
</Badge>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import queryString from "query-string";
|
|||||||
import pulpGif from "../static/images/pulp.gif";
|
import pulpGif from "../static/images/pulp.gif";
|
||||||
import NavBar from "./NavBar";
|
import NavBar from "./NavBar";
|
||||||
|
|
||||||
const apiUrl = process.env.REACT_APP_APIUrl;
|
const apiUrl = process.env.REACT_APP_API_URL;
|
||||||
|
|
||||||
const paginationTheme = createTheme({
|
const paginationTheme = createTheme({
|
||||||
palette: {
|
palette: {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import CloudDoneOutlinedIcon from "@mui/icons-material/CloudDoneOutlined";
|
|||||||
import { useDropzone } from "react-dropzone";
|
import { useDropzone } from "react-dropzone";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
|
||||||
const apiUrl = process.env.REACT_APP_APIUrl;
|
const apiUrl = process.env.REACT_APP_API_URL;
|
||||||
|
|
||||||
const UploadDiary = () => {
|
const UploadDiary = () => {
|
||||||
const [file, setFile] = useState(null);
|
const [file, setFile] = useState(null);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
@use "./scss/posterSelector";
|
@use "./scss/posterSelector";
|
||||||
@use "./scss/posterGallery";
|
@use "./scss/posterGallery";
|
||||||
@use "./scss/cart";
|
@use "./scss/cart";
|
||||||
|
@use "./scss/navbar";
|
||||||
|
|
||||||
.App {
|
.App {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|||||||
@@ -1,90 +1,55 @@
|
|||||||
// Variables
|
// _cart.scss
|
||||||
$primary-color: #00a346;
|
|
||||||
$secondary-color: #3498db;
|
|
||||||
$background-dark: #2c3e50;
|
|
||||||
$background-light: #34495e;
|
|
||||||
$text-white: #ecf0f1;
|
|
||||||
$text-muted: #95a5a6;
|
|
||||||
$hover-scale: 1.05;
|
|
||||||
$gap-spacing: 1rem;
|
|
||||||
|
|
||||||
.cart-container {
|
.cart-container {
|
||||||
margin-top: 2rem;
|
padding: 2rem;
|
||||||
margin-bottom: 4rem;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: $gap-spacing;
|
gap: 2rem;
|
||||||
|
|
||||||
.poster-list {
|
.poster-grid {
|
||||||
flex: 2;
|
flex: 1;
|
||||||
margin-right: 2rem;
|
display: grid;
|
||||||
max-height: calc(100vh - 200px);
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
gap: 1rem;
|
||||||
|
max-height: calc(100vh - 4rem);
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
padding-right: 1rem;
|
||||||
.cart-title {
|
|
||||||
color: $text-white;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
font-size: 2rem;
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
||||||
|
|
||||||
.poster-card {
|
.poster-card {
|
||||||
display: flex;
|
position: relative;
|
||||||
margin-bottom: 1rem;
|
aspect-ratio: 2/3;
|
||||||
background-color: $background-dark;
|
border-radius: 8px;
|
||||||
border-radius: 4px;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
.poster-media {
|
&:hover .delete-overlay {
|
||||||
width: 120px;
|
opacity: 1;
|
||||||
height: 180px;
|
}
|
||||||
|
|
||||||
|
.poster-image {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
border-radius: 4px 0 0 4px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.poster-content {
|
.delete-overlay {
|
||||||
flex-grow: 1;
|
position: absolute;
|
||||||
padding: 1rem;
|
inset: 0;
|
||||||
display: flex;
|
background-color: rgba(0, 0, 0, 0.7);
|
||||||
flex-direction: column;
|
|
||||||
justify-content: space-between;
|
|
||||||
|
|
||||||
.poster-title {
|
|
||||||
color: $text-white;
|
|
||||||
font-size: 1.25rem;
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.poster-id {
|
|
||||||
color: $text-muted;
|
|
||||||
font-size: 1rem;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.poster-actions {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
gap: 0.5rem;
|
|
||||||
|
|
||||||
.action-button {
|
|
||||||
flex-grow: 1;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.2s ease;
|
||||||
|
|
||||||
|
.delete-button {
|
||||||
|
background-color: #e74c3c;
|
||||||
|
border: none;
|
||||||
|
color: white;
|
||||||
padding: 0.5rem;
|
padding: 0.5rem;
|
||||||
border-radius: 4px;
|
border-radius: 50%;
|
||||||
background-color: transparent;
|
cursor: pointer;
|
||||||
border: 1px solid $text-muted;
|
transition: transform 0.2s ease;
|
||||||
color: $text-white;
|
|
||||||
transition: background-color 0.3s ease;
|
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: $background-light;
|
transform: scale(1.1);
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:not(:last-child) {
|
|
||||||
margin-right: 0.5rem;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -92,75 +57,49 @@ $gap-spacing: 1rem;
|
|||||||
}
|
}
|
||||||
|
|
||||||
.action-panel {
|
.action-panel {
|
||||||
flex: 1;
|
width: 300px;
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: 2rem;
|
top: 2rem;
|
||||||
height: fit-content;
|
background-color: #34495e;
|
||||||
padding: 1.5rem;
|
|
||||||
background-color: $background-light;
|
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
|
padding: 1.5rem;
|
||||||
|
height: fit-content;
|
||||||
|
|
||||||
.action-title {
|
h2 {
|
||||||
color: $text-white;
|
color: white;
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1.5rem;
|
||||||
font-size: 1.5rem;
|
font-size: 1.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-control {
|
.format-select {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-bottom: 1.5rem;
|
margin-bottom: 1.5rem;
|
||||||
color: $text-white;
|
|
||||||
|
|
||||||
select {
|
|
||||||
background-color: $background-dark;
|
|
||||||
color: $text-white;
|
|
||||||
padding: 0.5rem;
|
padding: 0.5rem;
|
||||||
border: 1px solid $text-muted;
|
background-color: #2c3e50;
|
||||||
|
border: 1px solid #95a5a6;
|
||||||
|
color: white;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.action-buttons {
|
.download-button {
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 1rem;
|
|
||||||
|
|
||||||
.primary-button,
|
|
||||||
.secondary-button {
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 0.75rem;
|
padding: 0.75rem;
|
||||||
|
background-color: #00a346;
|
||||||
|
color: white;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
font-size: 1rem;
|
margin-bottom: 1rem;
|
||||||
font-weight: bold;
|
cursor: pointer;
|
||||||
transition: background-color 0.3s ease;
|
transition: background-color 0.2s ease;
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
&.primary-button {
|
|
||||||
background-color: $primary-color;
|
|
||||||
color: $text-white;
|
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: darken($primary-color, 10%);
|
background-color: darken(#00a346, 10%);
|
||||||
}
|
}
|
||||||
|
|
||||||
&:disabled {
|
&:disabled {
|
||||||
background-color: darken($primary-color, 20%);
|
background-color: darken(#00a346, 20%);
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.secondary-button {
|
|
||||||
background-color: $secondary-color;
|
|
||||||
color: $text-white;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: darken($secondary-color, 10%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
32
src/styles/scss/_navbar.scss
Normal file
32
src/styles/scss/_navbar.scss
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
// _navbar.scss
|
||||||
|
|
||||||
|
// Variables de couleur et autres constantes
|
||||||
|
$background-color: #1c1f23;
|
||||||
|
$icon-color: white;
|
||||||
|
$margin-right: 8px; // Correspondant à theme.spacing(2)
|
||||||
|
|
||||||
|
.navbar {
|
||||||
|
top: auto !important;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: $background-color !important;
|
||||||
|
|
||||||
|
.toolbar {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.back-button,
|
||||||
|
.cart-button,
|
||||||
|
.refresh-button {
|
||||||
|
color: $icon-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.refresh-button {
|
||||||
|
margin-right: $margin-right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.back-button[disabled] {
|
||||||
|
opacity: 0.3;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -151,6 +151,7 @@ $hover-color: rgba(102, 119, 136, 0.2);
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
height: 400px;
|
height: 400px;
|
||||||
|
color: $text-white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.gif-container {
|
.gif-container {
|
||||||
|
|||||||
Reference in New Issue
Block a user