CSS Style Anpassungen

This commit is contained in:
Matthias Lotz 2025-10-19 20:34:51 +02:00
parent 16f53a129a
commit 2a8cedd512
12 changed files with 106 additions and 200 deletions

View File

@ -0,0 +1,6 @@
/* Styles extracted from GroupImagesPage makeStyles */
.group-images-container { padding-top: 20px; padding-bottom: 40px; min-height: 80vh; }
.group-card { border-radius: 12px; box-shadow: 0 4px 12px rgba(0,0,0,0.1); padding: 20px; margin-bottom: 20px; }
.header-text { font-family: roboto; font-weight: 400; font-size: 28px; text-align: center; margin-bottom: 10px; color: #333333; }
.subheader-text { font-family: roboto; font-weight: 300; font-size: 16px; color: #666666; text-align: center; margin-bottom: 30px; }
.action-buttons { display: flex; gap: 15px; justify-content: center; margin-top: 20px; flex-wrap: wrap; }

View File

@ -0,0 +1,20 @@
/* Extracted styles from GroupsOverviewPage makeStyles */
.groups-overview-container { padding-top: 20px; padding-bottom: 40px; min-height: 80vh; }
.header-card { border-radius: 12px; box-shadow: 0 4px 12px rgba(0,0,0,0.1); margin-bottom: 30px; text-align: center; padding: 20px; }
.header-title { font-family: roboto; font-weight: 500; font-size: 28px; color: #333333; margin-bottom: 10px; }
.header-subtitle { font-family: roboto; font-size: 16px; color: #666666; margin-bottom: 20px; }
.group-card { border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); transition: all 0.3s ease; height: 100%; display: flex; flex-direction: column; }
.group-card:hover { transform: translateY(-4px); box-shadow: 0 8px 20px rgba(0,0,0,0.15); }
.group-image { height: 180px; object-fit: cover; }
.group-content { flex-grow: 1; display: flex; flex-direction: column; }
.group-title { font-family: roboto; font-weight: 500; font-size: 16px; color: #333333; margin-bottom: 8px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.group-meta { font-size: 12px; color: #999999; margin-bottom: 15px; }
.group-actions { margin-top: auto; display: flex; gap: 8px; justify-content: space-between; }
.view-button { border-radius: 20px; text-transform: none; font-size: 12px; padding: 6px 16px; background: linear-gradient(45deg, #4CAF50 30%, #45a049 90%); color: white; }
.view-button:hover { background: linear-gradient(45deg, #45a049 30%, #4CAF50 90%); }
.action-buttons { display:flex; gap:15px; justify-content:center; flex-wrap: wrap; margin-top:20px; }
.primary-button { border-radius: 25px; padding: 12px 30px; font-size:16px; font-weight:500; text-transform:none; background: linear-gradient(45deg, #2196F3 30%, #1976D2 90%); color:white; }
.home-button { border-radius:25px; padding:12px 30px; font-size:16px; font-weight:500; text-transform:none; border:2px solid #4CAF50; color:#4CAF50; background-color: transparent; }
.empty-state { text-align:center; padding:60px 20px; }
.loading-container { text-align:center; padding:60px 20px; }
@media (max-width:800px) { .nav__links, .cta { display:none; } }

View File

@ -51,6 +51,14 @@ header {
color: #0088a9; color: #0088a9;
} }
/* Active nav link */
.nav__links li a.active {
background-color: #72b12b; /* requested dark green */
padding: 6px 12px;
border-radius: 6px;
color: #ffffff;
}
.cta { .cta {
margin-left: 20px; margin-left: 20px;
padding: 9px 25px; padding: 9px 25px;

View File

@ -1,4 +1,5 @@
import React from 'react' import React from 'react'
import { NavLink } from 'react-router-dom'
import '../Css/Navbar.css' import '../Css/Navbar.css'
@ -8,16 +9,16 @@ import { Lock as LockIcon } from '@material-ui/icons';
function Navbar() { function Navbar() {
return ( return (
<header> <header>
<div className="logo"><a className="logo" href="/"><img src={logo} className="imageNav" alt="Logo"/><p className="logo">Upload your Project Images</p></a></div> <div className="logo"><NavLink className="logo" exact to="/"><img src={logo} className="imageNav" alt="Logo"/><p className="logo">Upload your Project Images</p></NavLink></div>
<nav> <nav>
<ul className="nav__links"> <ul className="nav__links">
<li><a href="/groups">Groups</a></li> <li><NavLink to="/groups" activeClassName="active">Groups</NavLink></li>
<li><a href="/slideshow">Slideshow</a></li> <li><NavLink to="/slideshow" activeClassName="active">Slideshow</NavLink></li>
<li><a href="/moderation"><LockIcon style={{ fontSize: 18, verticalAlign: 'text-bottom', marginRight: 6 }} aria-hidden="true" />Moderation</a></li> <li><NavLink to="/moderation" activeClassName="active"><LockIcon style={{ fontSize: 18, verticalAlign: 'text-bottom', marginRight: 6 }} aria-hidden="true" />Moderation</NavLink></li>
<li><a href="https://www.hobbyhimmel.de/ueber-uns/konzept/">About</a></li> <li><a href="https://www.hobbyhimmel.de/ueber-uns/konzept/">About</a></li>
</ul> </ul>
</nav> </nav>
<a className="cta" href="/">Upload</a> <NavLink className="cta" exact to="/">Upload</NavLink>
</header> </header>
) )
} }

View File

@ -0,0 +1,4 @@
/* Background utilities copied from ComponentUtils/Css/Background.css */
.allContainer { display: flex; flex-direction: column; min-height: 100vh; }
.footerContainer { margin-top: auto; }
.moderation-loading, .moderation-error { padding: 40px; text-align: center; }

View File

@ -0,0 +1,6 @@
/* Copied from ComponentUtils/Css/GroupImagesPage.css and moved to Pages/Css */
.group-images-container { padding-top: 20px; padding-bottom: 40px; min-height: 80vh; }
.group-card { border-radius: 12px; box-shadow: 0 4px 12px rgba(0,0,0,0.1); padding: 20px; margin-bottom: 20px; }
.header-text { font-family: roboto; font-weight: 400; font-size: 28px; text-align: center; margin-bottom: 10px; color: #333333; }
.subheader-text { font-family: roboto; font-weight: 300; font-size: 16px; color: #666666; text-align: center; margin-bottom: 30px; }
.action-buttons { display: flex; gap: 15px; justify-content: center; margin-top: 20px; flex-wrap: wrap; }

View File

@ -0,0 +1,20 @@
/* Copied from ComponentUtils/Css/GroupsOverviewPage.css and moved to Pages/Css */
.groups-overview-container { padding-top: 20px; padding-bottom: 40px; min-height: 80vh; }
.header-card { border-radius: 12px; box-shadow: 0 4px 12px rgba(0,0,0,0.1); margin-bottom: 30px; text-align: center; padding: 20px; }
.header-title { font-family: roboto; font-weight: 500; font-size: 28px; color: #333333; margin-bottom: 10px; }
.header-subtitle { font-family: roboto; font-size: 16px; color: #666666; margin-bottom: 20px; }
.group-card { border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); transition: all 0.3s ease; height: 100%; display: flex; flex-direction: column; }
.group-card:hover { transform: translateY(-4px); box-shadow: 0 8px 20px rgba(0,0,0,0.15); }
.group-image { height: 180px; object-fit: cover; }
.group-content { flex-grow: 1; display: flex; flex-direction: column; }
.group-title { font-family: roboto; font-weight: 500; font-size: 16px; color: #333333; margin-bottom: 8px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.group-meta { font-size: 12px; color: #999999; margin-bottom: 15px; }
.group-actions { margin-top: auto; display: flex; gap: 8px; justify-content: space-between; }
.view-button { border-radius: 20px; text-transform: none; font-size: 12px; padding: 6px 16px; background: linear-gradient(45deg, #4CAF50 30%, #45a049 90%); color: white; }
.view-button:hover { background: linear-gradient(45deg, #45a049 30%, #4CAF50 90%); }
.action-buttons { display:flex; gap:15px; justify-content:center; flex-wrap: wrap; margin-top:20px; }
.primary-button { border-radius: 25px; padding: 12px 30px; font-size:16px; font-weight:500; text-transform:none; background: linear-gradient(45deg, #2196F3 30%, #1976D2 90%); color:white; }
.home-button { border-radius:25px; padding:12px 30px; font-size:16px; font-weight:500; text-transform:none; border:2px solid #4CAF50; color:#4CAF50; background-color: transparent; }
.empty-state { text-align:center; padding:60px 20px; }
.loading-container { text-align:center; padding:60px 20px; }
@media (max-width:800px) { .nav__links, .cta { display:none; } }

View File

@ -1,6 +1,5 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { useParams, useHistory } from 'react-router-dom'; import { useParams, useHistory } from 'react-router-dom';
import { makeStyles } from '@material-ui/core/styles';
import { Button, Card, CardContent, Typography, Container } from '@material-ui/core'; import { Button, Card, CardContent, Typography, Container } from '@material-ui/core';
import Swal from 'sweetalert2/dist/sweetalert2.js'; import Swal from 'sweetalert2/dist/sweetalert2.js';
import 'sweetalert2/src/sweetalert2.scss'; import 'sweetalert2/src/sweetalert2.scss';
@ -11,47 +10,12 @@ import Footer from '../ComponentUtils/Footer';
import ImagePreviewGallery from '../ComponentUtils/MultiUpload/ImagePreviewGallery'; import ImagePreviewGallery from '../ComponentUtils/MultiUpload/ImagePreviewGallery';
import DescriptionInput from '../ComponentUtils/MultiUpload/DescriptionInput'; import DescriptionInput from '../ComponentUtils/MultiUpload/DescriptionInput';
import '../ComponentUtils/Css/Background.css'; import '../Pages/Css/Background.css';
const useStyles = makeStyles({ import '../Pages/Css/GroupImagesPage.css';
container: {
paddingTop: '20px',
paddingBottom: '40px',
minHeight: '80vh'
},
card: {
borderRadius: '12px',
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.1)',
padding: '20px',
marginBottom: '20px'
},
headerText: {
fontFamily: 'roboto',
fontWeight: '400',
fontSize: '28px',
textAlign: 'center',
marginBottom: '10px',
color: '#333333'
},
subheaderText: {
fontFamily: 'roboto',
fontWeight: '300',
fontSize: '16px',
color: '#666666',
textAlign: 'center',
marginBottom: '30px'
},
actionButtons: {
display: 'flex',
gap: '15px',
justifyContent: 'center',
marginTop: '20px',
flexWrap: 'wrap'
}
});
const GroupImagesPage = () => { const GroupImagesPage = () => {
const classes = useStyles(); // use CSS classes from GroupImagesPage.css
const { groupId } = useParams(); const { groupId } = useParams();
const history = useHistory(); const history = useHistory();
const [group, setGroup] = useState(null); const [group, setGroup] = useState(null);
@ -172,11 +136,11 @@ const GroupImagesPage = () => {
<div className="allContainer"> <div className="allContainer">
<Navbar /> <Navbar />
<Container maxWidth="lg" className={classes.container}> <Container maxWidth="lg" className="group-images-container">
<Card className={classes.card}> <Card className="group-card">
<CardContent> <CardContent>
<Typography className={classes.headerText}>Gruppe bearbeiten</Typography> <Typography className="header-text">Gruppe bearbeiten</Typography>
<Typography className={classes.subheaderText}>{group.title || ''}</Typography> <Typography className="subheader-text">{group.title || ''}</Typography>
<ImagePreviewGallery images={selectedImages} onRemoveImage={handleRemoveImage} /> <ImagePreviewGallery images={selectedImages} onRemoveImage={handleRemoveImage} />
@ -184,7 +148,7 @@ const GroupImagesPage = () => {
<> <>
<DescriptionInput metadata={metadata} onMetadataChange={setMetadata} /> <DescriptionInput metadata={metadata} onMetadataChange={setMetadata} />
<div className={classes.actionButtons}> <div className="action-buttons">
<Button variant="outlined" onClick={() => history.push('/moderation')}> Zurück</Button> <Button variant="outlined" onClick={() => history.push('/moderation')}> Zurück</Button>
<Button color="primary" variant="contained" onClick={handleSave} disabled={saving}>{saving ? 'Speichern...' : 'Speichern'}</Button> <Button color="primary" variant="contained" onClick={handleSave} disabled={saving}>{saving ? 'Speichern...' : 'Speichern'}</Button>
</div> </div>

View File

@ -1,7 +1,7 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { useHistory } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
import { Helmet } from 'react-helmet'; import { Helmet } from 'react-helmet';
import { makeStyles } from '@material-ui/core/styles'; import '../Pages/Css/GroupsOverviewPage.css';
import { import {
Container, Container,
Card, Card,
@ -30,135 +30,10 @@ import { fetchAllGroups, deleteGroup } from '../../Utils/batchUpload';
// Styles // Styles
import '../../App.css'; import '../../App.css';
import '../ComponentUtils/Css/Background.css'; import '../Pages/Css/Background.css';
const useStyles = makeStyles({
container: {
paddingTop: '20px',
paddingBottom: '40px',
minHeight: '80vh'
},
headerCard: {
borderRadius: '12px',
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.1)',
marginBottom: '30px',
textAlign: 'center',
padding: '20px'
},
headerTitle: {
fontFamily: 'roboto',
fontWeight: '500',
fontSize: '28px',
color: '#333333',
marginBottom: '10px'
},
headerSubtitle: {
fontFamily: 'roboto',
fontSize: '16px',
color: '#666666',
marginBottom: '20px'
},
groupCard: {
borderRadius: '12px',
boxShadow: '0 2px 8px rgba(0, 0, 0, 0.1)',
transition: 'all 0.3s ease',
height: '100%',
display: 'flex',
flexDirection: 'column',
'&:hover': {
transform: 'translateY(-4px)',
boxShadow: '0 8px 20px rgba(0, 0, 0, 0.15)'
}
},
groupImage: {
height: '180px',
objectFit: 'cover'
},
groupContent: {
flexGrow: 1,
display: 'flex',
flexDirection: 'column'
},
groupTitle: {
fontFamily: 'roboto',
fontWeight: '500',
fontSize: '16px',
color: '#333333',
marginBottom: '8px',
display: '-webkit-box',
WebkitLineClamp: 2,
WebkitBoxOrient: 'vertical',
overflow: 'hidden'
},
groupMeta: {
fontSize: '12px',
color: '#999999',
marginBottom: '15px'
},
groupActions: {
marginTop: 'auto',
display: 'flex',
gap: '8px',
justifyContent: 'space-between'
},
viewButton: {
borderRadius: '20px',
textTransform: 'none',
fontSize: '12px',
padding: '6px 16px',
background: 'linear-gradient(45deg, #4CAF50 30%, #45a049 90%)',
color: 'white',
'&:hover': {
background: 'linear-gradient(45deg, #45a049 30%, #4CAF50 90%)'
}
},
actionButtons: {
display: 'flex',
gap: '15px',
justifyContent: 'center',
flexWrap: 'wrap',
marginTop: '20px'
},
primaryButton: {
borderRadius: '25px',
padding: '12px 30px',
fontSize: '16px',
fontWeight: '500',
textTransform: 'none',
background: 'linear-gradient(45deg, #2196F3 30%, #1976D2 90%)',
color: 'white',
'&:hover': {
background: 'linear-gradient(45deg, #1976D2 30%, #2196F3 90%)',
transform: 'translateY(-2px)'
}
},
homeButton: {
borderRadius: '25px',
padding: '12px 30px',
fontSize: '16px',
fontWeight: '500',
textTransform: 'none',
border: '2px solid #4CAF50',
color: '#4CAF50',
backgroundColor: 'transparent',
'&:hover': {
backgroundColor: '#4CAF50',
color: 'white',
transform: 'translateY(-2px)'
}
},
emptyState: {
textAlign: 'center',
padding: '60px 20px'
},
loadingContainer: {
textAlign: 'center',
padding: '60px 20px'
}
});
function GroupsOverviewPage() { function GroupsOverviewPage() {
const classes = useStyles(); // use CSS classes from GroupsOverviewPage.css
const history = useHistory(); const history = useHistory();
const [groups, setGroups] = useState([]); const [groups, setGroups] = useState([]);
@ -207,8 +82,8 @@ function GroupsOverviewPage() {
return ( return (
<div className="allContainer"> <div className="allContainer">
<Navbar /> <Navbar />
<Container maxWidth="lg" className={classes.container}> <Container maxWidth="lg" className="groups-overview-container">
<div className={classes.loadingContainer}> <div className="loading-container">
<CircularProgress size={60} color="primary" /> <CircularProgress size={60} color="primary" />
<Typography variant="h6" style={{ marginTop: '20px', color: '#666666' }}> <Typography variant="h6" style={{ marginTop: '20px', color: '#666666' }}>
Slideshows werden geladen... Slideshows werden geladen...
@ -230,19 +105,19 @@ function GroupsOverviewPage() {
</Helmet> </Helmet>
<Navbar /> <Navbar />
<Container maxWidth="lg" className={classes.container}> <Container maxWidth="lg" className="groups-overview-container">
{/* Header */} {/* Header */}
<Card className={classes.headerCard}> <Card className="header-card">
<Typography className={classes.headerTitle}> <Typography className="header-title">
🎬 Alle Slideshows 🎬 Alle Slideshows
</Typography> </Typography>
<Typography className={classes.headerSubtitle}> <Typography className="header-subtitle">
Verwalten Sie Ihre hochgeladenen Bildersammlungen Verwalten Sie Ihre hochgeladenen Bildersammlungen
</Typography> </Typography>
<div className={classes.actionButtons}> <div className="action-buttons">
<Button <Button
className={classes.primaryButton} className="primary-button"
onClick={handleCreateNew} onClick={handleCreateNew}
startIcon={<AddIcon />} startIcon={<AddIcon />}
size="large" size="large"
@ -251,7 +126,7 @@ function GroupsOverviewPage() {
</Button> </Button>
<Button <Button
className={classes.homeButton} className="home-button"
onClick={handleGoHome} onClick={handleGoHome}
startIcon={<HomeIcon />} startIcon={<HomeIcon />}
size="large" size="large"
@ -263,27 +138,27 @@ function GroupsOverviewPage() {
{/* Groups Grid */} {/* Groups Grid */}
{error ? ( {error ? (
<div className={classes.emptyState}> <div className="empty-state">
<Typography variant="h6" style={{ color: '#f44336', marginBottom: '20px' }}> <Typography variant="h6" style={{ color: '#f44336', marginBottom: '20px' }}>
😕 Fehler beim Laden 😕 Fehler beim Laden
</Typography> </Typography>
<Typography variant="body1" style={{ color: '#666666', marginBottom: '30px' }}> <Typography variant="body1" style={{ color: '#666666', marginBottom: '30px' }}>
{error} {error}
</Typography> </Typography>
<Button onClick={loadGroups} className={classes.primaryButton}> <Button onClick={loadGroups} className="primary-button">
🔄 Erneut versuchen 🔄 Erneut versuchen
</Button> </Button>
</div> </div>
) : groups.length === 0 ? ( ) : groups.length === 0 ? (
<div className={classes.emptyState}> <div className="empty-state">
<Typography variant="h4" style={{ color: '#666666', marginBottom: '20px' }}> <Typography variant="h4" style={{ color: '#666666', marginBottom: '20px' }}>
📸 Keine Slideshows vorhanden 📸 Keine Slideshows vorhanden
</Typography> </Typography>
<Typography variant="body1" style={{ color: '#999999', marginBottom: '30px' }}> <Typography variant="body1" style={{ color: '#999999', marginBottom: '30px' }}>
Erstellen Sie Ihre erste Slideshow, indem Sie mehrere Bilder hochladen. Erstellen Sie Ihre erste Slideshow, indem Sie mehrere Bilder hochladen.
</Typography> </Typography>
<Button <Button
className={classes.primaryButton} className="primary-button"
onClick={handleCreateNew} onClick={handleCreateNew}
size="large" size="large"
> >
@ -301,28 +176,28 @@ function GroupsOverviewPage() {
<Grid container spacing={3}> <Grid container spacing={3}>
{groups.map((group) => ( {groups.map((group) => (
<Grid item xs={12} sm={6} md={4} key={group.groupId}> <Grid item xs={12} sm={6} md={4} key={group.groupId}>
<Card className={classes.groupCard}> <Card className="group-card">
{group.images && group.images.length > 0 && ( {group.images && group.images.length > 0 && (
<CardMedia <CardMedia
component="img" component="img"
className={classes.groupImage} className="group-image"
image={group.images[0].filePath} image={group.images[0].filePath}
alt={group.description || 'Slideshow Vorschau'} alt={group.description || 'Slideshow Vorschau'}
/> />
)} )}
<CardContent className={classes.groupContent}> <CardContent className="group-content">
<Typography className={classes.groupTitle}> <Typography className="group-title">
{group.description || 'Unbenannte Slideshow'} {group.description || 'Unbenannte Slideshow'}
</Typography> </Typography>
<Typography className={classes.groupMeta}> <Typography className="group-meta">
📅 {formatDate(group.uploadDate)} 📸 {group.images?.length || 0} Bilder 📅 {formatDate(group.uploadDate)} 📸 {group.images?.length || 0} Bilder
</Typography> </Typography>
<div className={classes.groupActions}> <div className="group-actions">
<Button <Button
className={classes.viewButton} className="view-button"
onClick={() => handleViewSlideshow(group.groupId)} onClick={() => handleViewSlideshow(group.groupId)}
startIcon={<SlideshowIcon />} startIcon={<SlideshowIcon />}
fullWidth fullWidth

View File

@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react';
import { Helmet } from 'react-helmet'; import { Helmet } from 'react-helmet';
import { useHistory } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
import './Css/ModerationPage.css'; import './Css/ModerationPage.css';
import Navbar from '../ComponentUtils/Headers/Navbar';
const ModerationPage = () => { const ModerationPage = () => {
const [groups, setGroups] = useState([]); const [groups, setGroups] = useState([]);
@ -147,6 +148,7 @@ const ModerationPage = () => {
return ( return (
<div className="moderation-page"> <div className="moderation-page">
<Navbar />
<Helmet> <Helmet>
<title>Moderation - Interne Verwaltung</title> <title>Moderation - Interne Verwaltung</title>
<meta name="robots" content="noindex, nofollow, nosnippet, noarchive" /> <meta name="robots" content="noindex, nofollow, nosnippet, noarchive" />

View File

@ -18,7 +18,7 @@ import { uploadImageBatch } from '../../Utils/batchUpload';
// Styles // Styles
import '../../App.css'; import '../../App.css';
import '../ComponentUtils/Css/Background.css'; import '../Pages/Css/Background.css';
const useStyles = makeStyles({ const useStyles = makeStyles({
container: { container: {

View File

@ -14,7 +14,7 @@ import 'sweetalert2/src/sweetalert2.scss'
import { sendRequest } from '../../Utils/sendRequest' import { sendRequest } from '../../Utils/sendRequest'
import '../ComponentUtils/Css/Background.css' import '../Pages/Css/Background.css'
const useStyles = makeStyles({ const useStyles = makeStyles({
multiUploadButton: { multiUploadButton: {