update readme due release on codeberg #2
184
setup.sh
184
setup.sh
|
@ -589,7 +589,7 @@ def export_pdf():
|
|||
img = Paragraph('', styles['Normal'])
|
||||
elif game.url and 'gog.com' in game.url:
|
||||
try:
|
||||
img_path = os.path.join(app.root_path, 'static', 'gog_logo.png')
|
||||
img_path = os.path.join(app.root_path, 'static', 'gog_logo.webp')
|
||||
img = Image(img_path, width=3*cm, height=img_height)
|
||||
except Exception:
|
||||
img = Paragraph('', styles['Normal'])
|
||||
|
@ -821,10 +821,11 @@ SHELL ["/bin/bash", "-c"]
|
|||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends wget \
|
||||
&& mkdir -p /app/static \
|
||||
&& wget -O /app/static/logo.png "https://git.nocci.it/nocci/GiftGamesDB/raw/branch/main/steam-gift-manager/static/logo.png" \
|
||||
&& wget -O /app/static/logo_small.png "https://git.nocci.it/nocci/GiftGamesDB/raw/branch/main/steam-gift-manager/static/logo_small.png" \
|
||||
&& wget -O /app/static/forgejo.svg "https://git.nocci.it/nocci/GiftGamesDB/raw/branch/main/steam-gift-manager/static/forgejo.svg" \
|
||||
&& wget -O /app/static/gog_logo.png "https://git.nocci.it/nocci/GameKeyManager/raw/branch/dev/steam-gift-manager/static/gog_logo.png" \
|
||||
&& wget -O /app/static/logo.webp "https://drop.nocadmin.net/logo.webp" \
|
||||
&& wget -O /app/static/logo_small.webp "https://drop.nocadmin.net/logo_small.webp" \
|
||||
&& wget -O /app/static/forgejo.webp "https://drop.nocadmin.net/forgejo.webp" \
|
||||
&& wget -O /app/static/gog_logo.webp "https://drop.nocadmin.net/gog_logo.webp" \
|
||||
&& wget -O /app/static/logo_small_maskable.webp "https://drop.nocadmin.net/logo_small_maskable.webp" \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN mkdir -p /app/data && \
|
||||
|
@ -945,6 +946,7 @@ chmod +x ../upgrade.sh
|
|||
# Manifest for PWA
|
||||
cat <<MANIFEST_END > static/manifest.json
|
||||
{
|
||||
"id": "/",
|
||||
"name": "Game Key Manager",
|
||||
"short_name": "GameKeys",
|
||||
"start_url": "/",
|
||||
|
@ -952,31 +954,44 @@ cat <<MANIFEST_END > static/manifest.json
|
|||
"background_color": "#212529",
|
||||
"theme_color": "#212529",
|
||||
"description": "Manage Steam/GOG keys easily!",
|
||||
"orientation": "any",
|
||||
"launch_handler": {
|
||||
"client_mode": "navigate-existing"
|
||||
},
|
||||
"icons": [
|
||||
{
|
||||
"src": "/static/logo_small.png",
|
||||
"src": "/static/logo_small.webp",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png",
|
||||
"purpose": "any maskable"
|
||||
"type": "image/webp",
|
||||
"purpose": "any"
|
||||
},
|
||||
{
|
||||
"src": "/static/logo.png",
|
||||
"src": "/static/logo_small_maskable.webp",
|
||||
"sizes": "192x192",
|
||||
"type": "image/webp",
|
||||
"purpose": "maskable"
|
||||
},
|
||||
{
|
||||
"src": "/static/logo.webp",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
"type": "image/webp",
|
||||
"purpose": "any maskable"
|
||||
}
|
||||
]
|
||||
}
|
||||
MANIFEST_END
|
||||
|
||||
|
||||
# Service Worker
|
||||
cat <<SW_END > static/serviceworker.js
|
||||
const CACHE_NAME = 'game-key-manager-v1';
|
||||
const ASSETS = [
|
||||
'/',
|
||||
'/static/style.css',
|
||||
'/static/logo.png',
|
||||
'/static/logo_small.png',
|
||||
'/static/gog_logo.png'
|
||||
'/static/logo.webp',
|
||||
'/static/logo_small.webp',
|
||||
'/static/gog_logo.webp',
|
||||
'/static/forgejo.webp'
|
||||
];
|
||||
|
||||
self.addEventListener('install', (event) => {
|
||||
|
@ -992,6 +1007,15 @@ self.addEventListener('fetch', (event) => {
|
|||
.then(cachedResponse => cachedResponse || fetch(event.request))
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener('activate', (event) => {
|
||||
event.waitUntil(
|
||||
caches.keys().then(keys => Promise.all(
|
||||
keys.filter(key => key !== CACHE_NAME)
|
||||
.map(key => caches.delete(key))
|
||||
))
|
||||
);
|
||||
});
|
||||
SW_END
|
||||
|
||||
|
||||
|
@ -1001,41 +1025,47 @@ mkdir -p templates static
|
|||
# Base Template
|
||||
cat <<HTML_END > templates/base.html
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ get_locale() }}" data-bs-theme="{{ theme }}">
|
||||
<html lang="{{ get_locale() if get_locale() in ['en', 'de'] else 'en' }}" data-bs-theme="{{ theme }}">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||
<title>{{ _('Game Key Manager') }}</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
|
||||
<link rel="manifest" href="{{ url_for('static', filename='manifest.json') }}">
|
||||
<meta name="description" content="Manage your Steam and GOG keys efficiently. Track redemption dates, share games, and export lists.">
|
||||
<meta name="theme-color" content="#212529">
|
||||
<title>{{ _('Game Key Manager') }}</title>
|
||||
<!-- PWA Manifest -->
|
||||
<link rel="manifest" href="{{ url_for('static', filename='manifest.json') }}">
|
||||
<!-- Preload Bootstrap CSS for better LCP -->
|
||||
<link rel="preload" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
|
||||
<noscript><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"></noscript>
|
||||
<!-- Critical CSS (Above-the-Fold) kann hier inline ergänzt werden -->
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-lg bg-body-tertiary">
|
||||
<div class="container">
|
||||
<a class="navbar-brand d-flex align-items-center gap-2" href="/">
|
||||
<img src="{{ url_for('static', filename='logo_small.png') }}" alt="Logo" width="150" height="116" style="object-fit:contain; border-radius:8px;">
|
||||
<span>Game Key Manager</span>
|
||||
<img src="{{ url_for('static', filename='logo_small.webp') }}" alt="Logo" width="150" height="116" style="object-fit:contain; border-radius:8px;">
|
||||
<span>Game Key Manager</span>
|
||||
</a>
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<form class="d-flex" action="{{ url_for('index') }}" method="GET">
|
||||
<input class="form-control me-2"
|
||||
type="search"
|
||||
<label for="searchInput" class="visually-hidden">{{ _('Search') }}</label>
|
||||
<input class="form-control me-2"
|
||||
type="search"
|
||||
name="q"
|
||||
id="searchInput"
|
||||
placeholder="{{ _('Search') }}"
|
||||
value="{{ search_query }}">
|
||||
<button class="btn btn-outline-success" type="submit">🔍</button>
|
||||
</form>
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input"
|
||||
type="checkbox"
|
||||
<input class="form-check-input"
|
||||
type="checkbox"
|
||||
id="darkModeSwitch" {% if theme == 'dark' %}checked{% endif %}>
|
||||
<label class="form-check-label" for="darkModeSwitch">{{ _('Dark Mode') }}</label>
|
||||
</div>
|
||||
<div class="dropdown ms-3">
|
||||
<!-- DEBUG: Current locale {{ get_locale() }} -->
|
||||
<div hidden id="locale-debug" data-locale="{{ get_locale() }}"></div>
|
||||
<button class="btn btn-outline-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
{% if get_locale() == 'de' %} Deutsch {% elif get_locale() == 'en' %} English {% else %} Sprache {% endif %}
|
||||
|
@ -1046,12 +1076,12 @@ cat <<HTML_END > templates/base.html
|
|||
</ul>
|
||||
</div>
|
||||
{% if current_user.is_authenticated %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{{ url_for('change_password') }}">🔒 {{ _('Password') }}</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{{ url_for('logout') }}">🚪 {{ _('Logout') }}</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{{ url_for('change_password') }}">🔒 {{ _('Password') }}</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{{ url_for('logout') }}">🚪 {{ _('Logout') }}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1071,29 +1101,31 @@ cat <<HTML_END > templates/base.html
|
|||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script>
|
||||
// Service Worker Registration for PWA
|
||||
if ('serviceWorker' in navigator) {
|
||||
window.addEventListener('load', () => {
|
||||
navigator.serviceWorker.register('{{ url_for("static", filename="serviceworker.js") }}', {scope: '/'})
|
||||
.then(registration => {
|
||||
console.log('ServiceWorker registered:', registration.scope);
|
||||
})
|
||||
.catch(error => {
|
||||
console.log('ServiceWorker registration failed:', error);
|
||||
});
|
||||
});
|
||||
}
|
||||
// Dark Mode Switch
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const toggle = document.getElementById('darkModeSwitch')
|
||||
const html = document.documentElement
|
||||
|
||||
toggle.addEventListener('change', function() {
|
||||
const theme = this.checked ? 'dark' : 'light'
|
||||
fetch('/set-theme/' + theme)
|
||||
.then(() => html.setAttribute('data-bs-theme', theme))
|
||||
})
|
||||
})
|
||||
if (toggle) {
|
||||
toggle.addEventListener('change', function() {
|
||||
const theme = this.checked ? 'dark' : 'light'
|
||||
fetch('/set-theme/' + theme)
|
||||
.then(() => html.setAttribute('data-bs-theme', theme))
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<script>
|
||||
if ('serviceWorker' in navigator) {
|
||||
window.addEventListener('load', function() {
|
||||
navigator.serviceWorker.register('/static/serviceworker.js')
|
||||
.then(function(registration) {
|
||||
console.log('ServiceWorker registered:', registration.scope);
|
||||
}, function(err) {
|
||||
console.log('ServiceWorker registration failed:', err);
|
||||
});
|
||||
});
|
||||
}
|
||||
</script>
|
||||
{% include "footer.html" %}
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1134,10 +1166,17 @@ cat <<HTML_END > templates/index.html
|
|||
<td>
|
||||
{% if game.steam_appid %}
|
||||
<img src="https://cdn.cloudflare.steamstatic.com/steam/apps/{{ game.steam_appid }}/header.jpg"
|
||||
alt="Steam Header" class="game-cover">
|
||||
alt="Steam Header"
|
||||
class="game-cover"
|
||||
{% if loop.first %}fetchpriority="high"{% endif %}
|
||||
width="368"
|
||||
height="172">
|
||||
{% elif game.url and 'gog.com' in game.url %}
|
||||
<img src="{{ url_for('static', filename='gog_logo.png') }}"
|
||||
alt="GOG Logo" class="game-cover">
|
||||
<img src="{{ url_for('static', filename='gog_logo.webp') }}"
|
||||
alt="GOG Logo"
|
||||
class="game-cover"
|
||||
width="368"
|
||||
height="172">
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ game.name }}</td>
|
||||
|
@ -1222,7 +1261,7 @@ cat <<HTML_END > templates/login.html
|
|||
<div class="col-md-6">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body text-center">
|
||||
<img src="{{ url_for('static', filename='logo.png') }}" alt="Logo" width="266" height="206" class="mb-4" style="object-fit:contain;">
|
||||
<img src="{{ url_for('static', filename='logo.webp') }}" alt="Logo" width="266" height="206" class="mb-4" style="object-fit:contain;">
|
||||
<h2 class="card-title mb-4">{{ _('Login') }}</h2>
|
||||
<form method="POST">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
|
@ -1545,7 +1584,7 @@ cat <<HTML_END > templates/footer.html
|
|||
</div>
|
||||
<div class="mb-2">
|
||||
<a href="https://git.nocci.it/nocci/GiftGamesDB" target="_blank" rel="noopener">
|
||||
<img src="{{ url_for('static', filename='forgejo.svg') }}" alt="forgejo" width="20" style="vertical-align:middle;margin-right:4px;">
|
||||
<img src="{{ url_for('static', filename='forgejo.webp') }}" alt="forgejo" width="20" style="vertical-align:middle;margin-right:4px;">
|
||||
find the source code on my Forgejo
|
||||
</a>
|
||||
</div>
|
||||
|
@ -1637,38 +1676,53 @@ body {
|
|||
transition: width 0.2s, height 0.2s;
|
||||
}
|
||||
|
||||
/* Responsiv für kleinere Bildschirme */
|
||||
/* Responsive Cover Images */
|
||||
.game-cover {
|
||||
width: 368px;
|
||||
height: 172px;
|
||||
object-fit: contain;
|
||||
background: #222;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
.game-cover {
|
||||
width: 260px;
|
||||
height: 122px;
|
||||
}
|
||||
}
|
||||
@media (max-width: 900px) {
|
||||
|
||||
@media (max-width: 992px) {
|
||||
.game-cover {
|
||||
width: 180px;
|
||||
height: 84px;
|
||||
}
|
||||
}
|
||||
@media (max-width: 600px) {
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.game-cover {
|
||||
width: 120px;
|
||||
height: 56px;
|
||||
}
|
||||
}
|
||||
@media (max-width: 400px) {
|
||||
|
||||
@media (max-width: 576px) {
|
||||
.game-cover {
|
||||
width: 90px;
|
||||
height: 42px;
|
||||
}
|
||||
}
|
||||
|
||||
img.game-cover {
|
||||
width: 368px;
|
||||
height: 172px;
|
||||
object-fit: contain;
|
||||
background: #222;
|
||||
border-radius: 8px;
|
||||
/* Accessibility Improvements */
|
||||
.visually-hidden {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
border: 0;
|
||||
}
|
||||
|
||||
CSS_END
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 740 B |
Binary file not shown.
After Width: | Height: | Size: 6.8 KiB |
Binary file not shown.
After Width: | Height: | Size: 8.1 KiB |
Binary file not shown.
After Width: | Height: | Size: 5.9 KiB |
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
Binary file not shown.
After Width: | Height: | Size: 2.5 KiB |
Loading…
Reference in New Issue