update pre commit skript, and responsive menu
This commit is contained in:
parent
b7acc01e90
commit
e48cf69b5d
|
|
@ -15,7 +15,7 @@ RUN npm install --production
|
|||
COPY backend/src ./src
|
||||
|
||||
# Copy production environment configuration
|
||||
#COPY docker/prod/backend/config/.env ./.env
|
||||
# COPY docker/prod/backend/config/.env ./.env
|
||||
|
||||
# Create data directories for file storage
|
||||
RUN mkdir -p src/data/images src/data/previews src/data/groups
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ services:
|
|||
environment:
|
||||
- REMOVE_IMAGES=false
|
||||
- NODE_ENV=production
|
||||
- ADMIN_SESSION_SECRET=MvFhivVIPIXvSGvWGfGOiQCkUJrmUsjWQTNGUgnSmtpsGHQlKruTBEBZgbVvOHHr
|
||||
- ADMIN_SESSION_SECRET=${ADMIN_SESSION_SECRET}
|
||||
- ADMIN_SESSION_DIR=/usr/src/app/src/data/sessions
|
||||
# ⚠️ Für HTTP-only Labs per Override auf "false" setzen (nicht im Repo committen)
|
||||
- ADMIN_SESSION_COOKIE_SECURE=true
|
||||
|
|
|
|||
|
|
@ -77,6 +77,38 @@ header {
|
|||
|
||||
.menu {
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
background: none;
|
||||
border: none;
|
||||
padding: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.menu span {
|
||||
width: 28px;
|
||||
height: 3px;
|
||||
background-color: #edf0f1;
|
||||
transition: transform 0.3s ease, opacity 0.3s ease;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.menu:focus-visible {
|
||||
outline: 2px solid #edf0f1;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.menu--open span:nth-child(1) {
|
||||
transform: translateY(9px) rotate(45deg);
|
||||
}
|
||||
|
||||
.menu--open span:nth-child(2) {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.menu--open span:nth-child(3) {
|
||||
transform: translateY(-9px) rotate(-45deg);
|
||||
}
|
||||
|
||||
.overlay {
|
||||
|
|
@ -121,6 +153,8 @@ header {
|
|||
font-size: 60px;
|
||||
color: #edf0f1;
|
||||
cursor: pointer;
|
||||
background: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
@media screen and (max-height: 450px) {
|
||||
|
|
@ -140,6 +174,6 @@ header {
|
|||
display: none;
|
||||
}
|
||||
.menu {
|
||||
display: initial;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React from 'react'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { NavLink, useLocation } from 'react-router-dom'
|
||||
|
||||
import '../Css/Navbar.css'
|
||||
|
|
@ -9,22 +9,67 @@ import { Lock as LockIcon } from '@mui/icons-material';
|
|||
function Navbar() {
|
||||
const location = useLocation();
|
||||
const isManagementPage = location.pathname.startsWith('/manage/');
|
||||
const [menuOpen, setMenuOpen] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setMenuOpen(false);
|
||||
}, [location.pathname]);
|
||||
|
||||
const toggleMenu = () => setMenuOpen(prev => !prev);
|
||||
const closeMenu = () => setMenuOpen(false);
|
||||
|
||||
return (
|
||||
<header>
|
||||
<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>
|
||||
<ul className="nav__links">
|
||||
<li><NavLink to="/groups" activeClassName="active">Groups</NavLink></li>
|
||||
<li><NavLink to="/moderation" activeClassName="active"><LockIcon style={{ fontSize: 18, verticalAlign: 'text-bottom', marginRight: 6 }} aria-hidden="true" />Moderation</NavLink></li>
|
||||
<li><NavLink className="cta" exact to="/" activeClassName="active">Upload</NavLink></li>
|
||||
<>
|
||||
<header>
|
||||
<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 aria-label="Hauptnavigation">
|
||||
<ul className="nav__links">
|
||||
<li><NavLink to="/groups" activeClassName="active">Groups</NavLink></li>
|
||||
<li><NavLink to="/moderation" activeClassName="active"><LockIcon style={{ fontSize: 18, verticalAlign: 'text-bottom', marginRight: 6 }} aria-hidden="true" />Moderation</NavLink></li>
|
||||
<li><NavLink className="cta" exact to="/" activeClassName="active">Upload</NavLink></li>
|
||||
{isManagementPage && (
|
||||
<li><NavLink className="cta" to={location.pathname} activeClassName="active">Mein Upload</NavLink></li>
|
||||
)}
|
||||
<li><a href="https://gitea.lan.hobbyhimmel.de/hobbyhimmel/Project-Image-Uploader" target="_blank" rel="noopener noreferrer">About</a></li>
|
||||
</ul>
|
||||
<button
|
||||
type="button"
|
||||
className={`menu${menuOpen ? ' menu--open' : ''}`}
|
||||
onClick={toggleMenu}
|
||||
aria-label="Navigation umschalten"
|
||||
aria-expanded={menuOpen}
|
||||
aria-controls="mobile-nav"
|
||||
>
|
||||
<span />
|
||||
<span />
|
||||
<span />
|
||||
</button>
|
||||
</nav>
|
||||
</header>
|
||||
<div
|
||||
id="mobile-nav"
|
||||
className={`overlay${menuOpen ? ' overlay--active' : ''}`}
|
||||
aria-hidden={!menuOpen}
|
||||
>
|
||||
<button type="button" className="close" onClick={closeMenu} aria-label="Navigation schließen">×</button>
|
||||
<div className="overlay__content">
|
||||
<NavLink to="/groups" activeClassName="active" onClick={closeMenu}>Groups</NavLink>
|
||||
<NavLink to="/moderation" activeClassName="active" onClick={closeMenu}>
|
||||
<LockIcon style={{ fontSize: 24, verticalAlign: 'text-bottom', marginRight: 12 }} aria-hidden="true" />Moderation
|
||||
</NavLink>
|
||||
<NavLink exact to="/" activeClassName="active" onClick={closeMenu}>Upload</NavLink>
|
||||
{isManagementPage && (
|
||||
<li><NavLink className="cta" to={location.pathname} activeClassName="active">Mein Upload</NavLink></li>
|
||||
<NavLink to={location.pathname} activeClassName="active" onClick={closeMenu}>Mein Upload</NavLink>
|
||||
)}
|
||||
<li><a href="https://gitea.lan.hobbyhimmel.de/hobbyhimmel/Project-Image-Uploader" target="_blank" rel="noopener noreferrer">About</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
<a href="https://gitea.lan.hobbyhimmel.de/hobbyhimmel/Project-Image-Uploader" target="_blank" rel="noopener noreferrer" onClick={closeMenu}>About</a>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,24 +1,59 @@
|
|||
import React from 'react'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { NavLink, useLocation } from 'react-router-dom'
|
||||
|
||||
import '../Css/Navbar.css'
|
||||
|
||||
import logo from '../../../Images/logo.png'
|
||||
import { Lock as LockIcon } from '@mui/icons-material';
|
||||
|
||||
function Navbar() {
|
||||
const location = useLocation();
|
||||
const isManagementPage = location.pathname.startsWith('/manage/');
|
||||
const [menuOpen, setMenuOpen] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setMenuOpen(false);
|
||||
}, [location.pathname]);
|
||||
|
||||
const toggleMenu = () => setMenuOpen(prev => !prev);
|
||||
const closeMenu = () => setMenuOpen(false);
|
||||
|
||||
return (
|
||||
<header>
|
||||
<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>
|
||||
<ul className="nav__links">
|
||||
<li><a href="https://gitea.lan.hobbyhimmel.de/hobbyhimmel/Project-Image-Uploader" target="_blank" rel="noopener noreferrer">About</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
<>
|
||||
<header>
|
||||
<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 aria-label="Hauptnavigation">
|
||||
<ul className="nav__links">
|
||||
<li><a href="https://gitea.lan.hobbyhimmel.de/hobbyhimmel/Project-Image-Uploader" target="_blank" rel="noopener noreferrer">About</a></li>
|
||||
</ul>
|
||||
<button
|
||||
type="button"
|
||||
className={`menu${menuOpen ? ' menu--open' : ''}`}
|
||||
onClick={toggleMenu}
|
||||
aria-label="Navigation umschalten"
|
||||
aria-expanded={menuOpen}
|
||||
aria-controls="mobile-nav-upload"
|
||||
>
|
||||
<span />
|
||||
<span />
|
||||
<span />
|
||||
</button>
|
||||
</nav>
|
||||
</header>
|
||||
<div
|
||||
id="mobile-nav-upload"
|
||||
className={`overlay${menuOpen ? ' overlay--active' : ''}`}
|
||||
aria-hidden={!menuOpen}
|
||||
>
|
||||
<button type="button" className="close" onClick={closeMenu} aria-label="Navigation schließen">×</button>
|
||||
<div className="overlay__content">
|
||||
<a href="https://gitea.lan.hobbyhimmel.de/hobbyhimmel/Project-Image-Uploader" target="_blank" rel="noopener noreferrer" onClick={closeMenu}>About</a>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,9 @@ ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|||
TARGET_FILE="$ROOT_DIR/docker/prod/docker-compose.yml"
|
||||
ANCHOR_LINE=" - ADMIN_SESSION_DIR=/usr/src/app/src/data/sessions"
|
||||
EXPECTED_LINE=" - ADMIN_SESSION_COOKIE_SECURE=true"
|
||||
SECRET_ANCHOR_LINE=' - NODE_ENV=production'
|
||||
SECRET_EXPECTED_LINE=' - ADMIN_SESSION_SECRET=${ADMIN_SESSION_SECRET}'
|
||||
SECRET_VALUE='${ADMIN_SESSION_SECRET}'
|
||||
|
||||
if [[ ! -f "$TARGET_FILE" ]]; then
|
||||
exit 0
|
||||
|
|
@ -13,6 +16,9 @@ fi
|
|||
export TARGET_FILE
|
||||
export ANCHOR_LINE
|
||||
export EXPECTED_LINE
|
||||
export SECRET_ANCHOR_LINE
|
||||
export SECRET_EXPECTED_LINE
|
||||
export SECRET_VALUE
|
||||
|
||||
result=$(python3 <<'PY'
|
||||
import os
|
||||
|
|
@ -23,30 +29,62 @@ import sys
|
|||
path = pathlib.Path(os.environ['TARGET_FILE'])
|
||||
anchor = os.environ['ANCHOR_LINE']
|
||||
expected = os.environ['EXPECTED_LINE']
|
||||
secret_anchor = os.environ['SECRET_ANCHOR_LINE']
|
||||
secret_expected = os.environ['SECRET_EXPECTED_LINE']
|
||||
secret_value = os.environ['SECRET_VALUE']
|
||||
|
||||
text = path.read_text()
|
||||
new_text = text
|
||||
changed = False
|
||||
|
||||
if 'ADMIN_SESSION_COOKIE_SECURE' in text:
|
||||
pattern = re.compile(r'(\-\s*ADMIN_SESSION_COOKIE_SECURE\s*=\s*)([^\n\r]+)')
|
||||
new_text, count = pattern.subn(r'\1true', text, count=1)
|
||||
if count:
|
||||
changed = new_text != text
|
||||
else:
|
||||
if anchor not in text:
|
||||
print('ERROR: Anchor line not found for ADMIN_SESSION_COOKIE_SECURE insertion', file=sys.stderr)
|
||||
sys.exit(2)
|
||||
new_text = text.replace(anchor, anchor + '\n' + expected, 1)
|
||||
changed = True
|
||||
cookie_pattern = re.compile(r'(\-\s*ADMIN_SESSION_COOKIE_SECURE\s*=\s*)([^\n\r]+)')
|
||||
secret_pattern = re.compile(r'(\-\s*ADMIN_SESSION_SECRET\s*=\s*)([^\n\r]+)')
|
||||
|
||||
def ensure_entry(text, *, pattern, value, anchor_line, expected_line, label):
|
||||
match = pattern.search(text)
|
||||
if match:
|
||||
desired = f"{match.group(1)}{value}"
|
||||
if match.group(0) == desired:
|
||||
return text, False
|
||||
return pattern.sub(lambda m: f"{m.group(1)}{value}", text, count=1), True
|
||||
if anchor_line not in text:
|
||||
print(f"ERROR: Anchor line not found for {label}", file=sys.stderr)
|
||||
sys.exit(2)
|
||||
return text.replace(anchor_line, anchor_line + '\n' + expected_line, 1), True
|
||||
|
||||
new_text, cookie_changed = ensure_entry(
|
||||
new_text,
|
||||
pattern=cookie_pattern,
|
||||
value='true',
|
||||
anchor_line=anchor,
|
||||
expected_line=expected,
|
||||
label='ADMIN_SESSION_COOKIE_SECURE'
|
||||
)
|
||||
changed = changed or cookie_changed
|
||||
|
||||
if expected not in new_text:
|
||||
print('ERROR: Failed to ensure ADMIN_SESSION_COOKIE_SECURE=true in docker-compose.yml', file=sys.stderr)
|
||||
sys.exit(3)
|
||||
print('ERROR: Failed to ensure ADMIN_SESSION_COOKIE_SECURE=true in docker-compose.yml', file=sys.stderr)
|
||||
sys.exit(3)
|
||||
|
||||
new_text, secret_changed = ensure_entry(
|
||||
new_text,
|
||||
pattern=secret_pattern,
|
||||
value=secret_value,
|
||||
anchor_line=secret_anchor,
|
||||
expected_line=secret_expected,
|
||||
label='ADMIN_SESSION_SECRET'
|
||||
)
|
||||
changed = changed or secret_changed
|
||||
|
||||
if secret_expected not in new_text:
|
||||
print('ERROR: Failed to ensure ADMIN_SESSION_SECRET uses environment variable in docker-compose.yml', file=sys.stderr)
|
||||
sys.exit(4)
|
||||
|
||||
if changed:
|
||||
path.write_text(new_text)
|
||||
print('UPDATED')
|
||||
path.write_text(new_text)
|
||||
print('UPDATED')
|
||||
else:
|
||||
print('UNCHANGED')
|
||||
print('UNCHANGED')
|
||||
PY
|
||||
)
|
||||
status=$?
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user