release nouri 0.5.1 mobile nav and header fixes
This commit is contained in:
@@ -4,8 +4,8 @@
|
|||||||
"author": "Florian Heinz",
|
"author": "Florian Heinz",
|
||||||
"description": "Private Flask app for meals, shopping and gentle food planning",
|
"description": "Private Flask app for meals, shopping and gentle food planning",
|
||||||
"tagline": "einfach essen planen",
|
"tagline": "einfach essen planen",
|
||||||
"version": "0.5.0",
|
"version": "0.5.1",
|
||||||
"upstreamVersion": "0.5.0",
|
"upstreamVersion": "0.5.1",
|
||||||
"healthCheckPath": "/",
|
"healthCheckPath": "/",
|
||||||
"httpPort": 8000,
|
"httpPort": 8000,
|
||||||
"manifestVersion": 2,
|
"manifestVersion": 2,
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
# Nouri 0.5.1
|
||||||
|
|
||||||
|
## Highlights
|
||||||
|
|
||||||
|
- Smartphone-Navigation unten neu als echte Erweiterung umgesetzt
|
||||||
|
- obere Nouri-Leiste auf kleinen Geräten nicht mehr sticky, sondern sauber fest positioniert
|
||||||
|
- PWA-Cache für frische Layout- und Einstellungsänderungen bereinigt
|
||||||
|
- Cloudron-Version auf `0.5.1` angehoben
|
||||||
|
|
||||||
|
## Neu in 0.5.1
|
||||||
|
|
||||||
|
### Mobile Navigation
|
||||||
|
|
||||||
|
- `Mehr` ist auf Smartphones kein schwebendes Overlay mehr.
|
||||||
|
- Die zusätzlichen Punkte klappen jetzt direkt aus der unteren Navigation heraus auf.
|
||||||
|
- Die Zusatzpunkte nutzen dieselbe kompakte Größe wie die unteren Menüpunkte.
|
||||||
|
- Der untere Navigationsbereich wird dabei nicht weichgezeichnet.
|
||||||
|
|
||||||
|
### Mobile Header
|
||||||
|
|
||||||
|
- Die obere Nouri-Leiste scrollt auf kleinen Geräten nicht mehr mit dem Inhalt.
|
||||||
|
- Die bisherige `sticky`-Logik für den Header wurde entfernt, damit es keine widersprüchlichen Zustände mehr gibt.
|
||||||
|
|
||||||
|
### PWA
|
||||||
|
|
||||||
|
- Der Service Worker verwendet einen aktualisierten Cache-Namen.
|
||||||
|
- Navigationsseiten werden frischer geladen, damit Änderungen an Einstellungen und Layout nicht an altem Cache hängen bleiben.
|
||||||
|
|
||||||
|
## Cloudron
|
||||||
|
|
||||||
|
- `CloudronManifest.json` wurde auf `0.5.1` angehoben.
|
||||||
|
- Damit lässt sich das Update sauber als neue App-Version ausrollen.
|
||||||
+1
-1
@@ -68,7 +68,7 @@ def create_app() -> Flask:
|
|||||||
PERMANENT_SESSION_LIFETIME=timedelta(days=30),
|
PERMANENT_SESSION_LIFETIME=timedelta(days=30),
|
||||||
SESSION_COOKIE_HTTPONLY=True,
|
SESSION_COOKIE_HTTPONLY=True,
|
||||||
SESSION_COOKIE_SAMESITE="Lax",
|
SESSION_COOKIE_SAMESITE="Lax",
|
||||||
APP_VERSION="0.5.0",
|
APP_VERSION="0.5.1",
|
||||||
VAPID_PUBLIC_KEY=os.environ.get("NOURI_VAPID_PUBLIC_KEY", ""),
|
VAPID_PUBLIC_KEY=os.environ.get("NOURI_VAPID_PUBLIC_KEY", ""),
|
||||||
VAPID_PRIVATE_KEY=os.environ.get("NOURI_VAPID_PRIVATE_KEY", ""),
|
VAPID_PRIVATE_KEY=os.environ.get("NOURI_VAPID_PRIVATE_KEY", ""),
|
||||||
VAPID_SUBJECT=os.environ.get("NOURI_VAPID_SUBJECT", "mailto:mail@hnz.io"),
|
VAPID_SUBJECT=os.environ.get("NOURI_VAPID_SUBJECT", "mailto:mail@hnz.io"),
|
||||||
|
|||||||
+95
-30
@@ -152,8 +152,7 @@ button.secondary:hover,
|
|||||||
}
|
}
|
||||||
|
|
||||||
.site-header {
|
.site-header {
|
||||||
position: sticky;
|
position: static;
|
||||||
top: 1rem;
|
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: auto 1fr auto;
|
grid-template-columns: auto 1fr auto;
|
||||||
@@ -969,6 +968,16 @@ legend {
|
|||||||
color: var(--accent-strong);
|
color: var(--accent-strong);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.menu-card-button {
|
||||||
|
width: 100%;
|
||||||
|
cursor: pointer;
|
||||||
|
font: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-card-form {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.roomy-row {
|
.roomy-row {
|
||||||
padding: 1rem 1.2rem;
|
padding: 1rem 1.2rem;
|
||||||
}
|
}
|
||||||
@@ -1191,6 +1200,10 @@ legend {
|
|||||||
backdrop-filter: blur(6px);
|
backdrop-filter: blur(6px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mobile-nav-stack {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.mobile-more-sheet {
|
.mobile-more-sheet {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
left: 0.75rem;
|
left: 0.75rem;
|
||||||
@@ -1223,6 +1236,10 @@ legend {
|
|||||||
margin: 1rem 0;
|
margin: 1rem 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mobile-menu-grid {
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
|
||||||
.mobile-sheet-actions {
|
.mobile-sheet-actions {
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
@@ -1241,9 +1258,19 @@ legend {
|
|||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body.has-mobile-nav {
|
||||||
|
padding-top: 5.3rem;
|
||||||
|
}
|
||||||
|
|
||||||
.site-header {
|
.site-header {
|
||||||
position: static;
|
position: fixed;
|
||||||
grid-template-columns: 1fr;
|
top: calc(env(safe-area-inset-top, 0px) + 0.5rem);
|
||||||
|
left: 0.5rem;
|
||||||
|
right: 0.5rem;
|
||||||
|
grid-template-columns: 1fr auto;
|
||||||
|
z-index: 30;
|
||||||
|
width: auto;
|
||||||
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stats-grid,
|
.stats-grid,
|
||||||
@@ -1273,13 +1300,12 @@ legend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.site-header {
|
.site-header {
|
||||||
position: sticky;
|
|
||||||
top: 0.7rem;
|
|
||||||
grid-template-columns: 1fr auto;
|
grid-template-columns: 1fr auto;
|
||||||
gap: 0.6rem;
|
gap: 0.6rem;
|
||||||
padding: 0.75rem 0.9rem;
|
padding: 0.75rem 0.9rem;
|
||||||
margin-bottom: 0.85rem;
|
margin-bottom: 0;
|
||||||
border-radius: 22px;
|
border-radius: 22px;
|
||||||
|
z-index: 30;
|
||||||
}
|
}
|
||||||
|
|
||||||
.desktop-nav,
|
.desktop-nav,
|
||||||
@@ -1377,54 +1403,95 @@ legend {
|
|||||||
min-width: 100%;
|
min-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mobile-bottom-nav {
|
.mobile-nav-stack {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
left: 0.75rem;
|
left: 0.75rem;
|
||||||
right: 0.75rem;
|
right: 0.75rem;
|
||||||
bottom: 0.75rem;
|
bottom: 0.75rem;
|
||||||
z-index: 20;
|
z-index: 24;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(5, minmax(0, 1fr));
|
|
||||||
gap: 0.35rem;
|
gap: 0.35rem;
|
||||||
padding: 0.5rem;
|
padding: 0.5rem;
|
||||||
border-radius: 22px;
|
border-radius: 22px;
|
||||||
background: var(--bg-elevated);
|
background: color-mix(in srgb, var(--bg) 96%, #f6decb 4%);
|
||||||
border: 1px solid var(--line);
|
border: 1px solid var(--line);
|
||||||
box-shadow: var(--shadow);
|
box-shadow: var(--shadow);
|
||||||
backdrop-filter: blur(26px) saturate(1.15);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.mobile-bottom-nav a {
|
.mobile-nav-extension {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-nav-stack.is-open .mobile-nav-extension {
|
||||||
display: grid;
|
display: grid;
|
||||||
justify-items: center;
|
|
||||||
gap: 0.28rem;
|
|
||||||
padding: 0.55rem 0.35rem;
|
|
||||||
border-radius: 16px;
|
|
||||||
color: var(--muted);
|
|
||||||
font-size: 0.78rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mobile-nav-extension,
|
||||||
|
.mobile-sheet-links.mobile-menu-grid {
|
||||||
|
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||||
|
gap: 0.35rem;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-extra-link,
|
||||||
|
.mobile-extra-button,
|
||||||
|
.mobile-bottom-nav a,
|
||||||
.mobile-nav-button {
|
.mobile-nav-button {
|
||||||
display: grid;
|
|
||||||
justify-items: center;
|
justify-items: center;
|
||||||
|
align-content: center;
|
||||||
|
display: grid;
|
||||||
|
min-height: 3.95rem;
|
||||||
|
padding: 0.55rem 0.2rem 0.5rem;
|
||||||
|
text-align: center;
|
||||||
gap: 0.28rem;
|
gap: 0.28rem;
|
||||||
padding: 0.55rem 0.35rem;
|
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
border: 0;
|
|
||||||
background: transparent;
|
background: transparent;
|
||||||
|
box-shadow: none;
|
||||||
color: var(--muted);
|
color: var(--muted);
|
||||||
font-size: 0.78rem;
|
font-size: 0.78rem;
|
||||||
|
border: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mobile-bottom-nav a.active,
|
.mobile-extra-link .ui-icon,
|
||||||
.mobile-nav-button.is-open {
|
.mobile-extra-button .ui-icon,
|
||||||
background: var(--accent-soft);
|
|
||||||
color: var(--text);
|
|
||||||
}
|
|
||||||
|
|
||||||
.mobile-bottom-nav .ui-icon {
|
.mobile-bottom-nav .ui-icon {
|
||||||
width: 1rem;
|
width: 1rem;
|
||||||
height: 1rem;
|
height: 1rem;
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-extra-link span:last-child,
|
||||||
|
.mobile-extra-button span:last-child,
|
||||||
|
.mobile-bottom-nav a span:last-child,
|
||||||
|
.mobile-nav-button span:last-child {
|
||||||
|
font-size: 0.72rem;
|
||||||
|
line-height: 1.08;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-extra-form {
|
||||||
|
display: contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-bottom-nav {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(5, minmax(0, 1fr));
|
||||||
|
gap: 0.35rem;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-bottom-nav a {
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-nav-button {
|
||||||
|
cursor: pointer;
|
||||||
|
font: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-bottom-nav a.active,
|
||||||
|
.mobile-extra-link.active,
|
||||||
|
.mobile-nav-button.is-open {
|
||||||
|
background: var(--accent-soft);
|
||||||
|
color: var(--text);
|
||||||
}
|
}
|
||||||
|
|
||||||
.mobile-profile-link {
|
.mobile-profile-link {
|
||||||
@@ -1438,8 +1505,6 @@ legend {
|
|||||||
height: 2.15rem;
|
height: 2.15rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mobile-sheet-head,
|
|
||||||
.mobile-sheet-actions,
|
|
||||||
.week-template-row {
|
.week-template-row {
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-12
@@ -1,32 +1,33 @@
|
|||||||
(() => {
|
(() => {
|
||||||
const initMobileSheet = () => {
|
const initMobileSheet = () => {
|
||||||
const sheet = document.querySelector("[data-mobile-sheet]");
|
const sheet = document.querySelector("[data-mobile-sheet]");
|
||||||
const backdrop = document.querySelector("[data-mobile-sheet-backdrop]");
|
const navStack = document.querySelector("[data-mobile-nav-stack]");
|
||||||
const openButtons = document.querySelectorAll("[data-mobile-sheet-open]");
|
const openButtons = document.querySelectorAll("[data-mobile-sheet-open]");
|
||||||
const closeButtons = document.querySelectorAll("[data-mobile-sheet-close]");
|
if (!sheet || !navStack || !openButtons.length) return;
|
||||||
if (!sheet || !backdrop || !openButtons.length) return;
|
|
||||||
|
|
||||||
const closeSheet = () => {
|
const closeSheet = () => {
|
||||||
sheet.hidden = true;
|
sheet.hidden = true;
|
||||||
backdrop.hidden = true;
|
navStack.classList.remove("is-open");
|
||||||
document.body.classList.remove("sheet-open");
|
|
||||||
openButtons.forEach((button) => button.classList.remove("is-open"));
|
openButtons.forEach((button) => button.classList.remove("is-open"));
|
||||||
};
|
};
|
||||||
|
|
||||||
const openSheet = () => {
|
const openSheet = () => {
|
||||||
sheet.hidden = false;
|
sheet.hidden = false;
|
||||||
backdrop.hidden = false;
|
navStack.classList.add("is-open");
|
||||||
document.body.classList.add("sheet-open");
|
|
||||||
openButtons.forEach((button) => button.classList.add("is-open"));
|
openButtons.forEach((button) => button.classList.add("is-open"));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const toggleSheet = () => {
|
||||||
|
if (sheet.hidden) {
|
||||||
|
openSheet();
|
||||||
|
} else {
|
||||||
|
closeSheet();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
openButtons.forEach((button) => {
|
openButtons.forEach((button) => {
|
||||||
button.addEventListener("click", openSheet);
|
button.addEventListener("click", toggleSheet);
|
||||||
});
|
});
|
||||||
closeButtons.forEach((button) => {
|
|
||||||
button.addEventListener("click", closeSheet);
|
|
||||||
});
|
|
||||||
backdrop.addEventListener("click", closeSheet);
|
|
||||||
|
|
||||||
document.addEventListener("keydown", (event) => {
|
document.addEventListener("keydown", (event) => {
|
||||||
if (event.key === "Escape") {
|
if (event.key === "Escape") {
|
||||||
@@ -37,6 +38,9 @@
|
|||||||
sheet.querySelectorAll("a").forEach((link) => {
|
sheet.querySelectorAll("a").forEach((link) => {
|
||||||
link.addEventListener("click", closeSheet);
|
link.addEventListener("click", closeSheet);
|
||||||
});
|
});
|
||||||
|
sheet.querySelectorAll("button[data-theme-toggle]").forEach((button) => {
|
||||||
|
button.addEventListener("click", closeSheet);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const initFilterInputs = () => {
|
const initFilterInputs = () => {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
const CACHE_NAME = "nouri-v0-5-1";
|
const CACHE_NAME = "nouri-v0-5-1-1";
|
||||||
const STATIC_ASSETS = [
|
const STATIC_ASSETS = [
|
||||||
"/static/css/styles.css",
|
"/static/css/styles.css",
|
||||||
"/static/js/theme.js",
|
"/static/js/theme.js",
|
||||||
|
|||||||
+22
-26
@@ -93,36 +93,31 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if g.user %}
|
{% if g.user %}
|
||||||
<div class="mobile-sheet-backdrop" data-mobile-sheet-backdrop hidden></div>
|
<div class="mobile-nav-stack" data-mobile-nav-stack>
|
||||||
<aside class="mobile-more-sheet" data-mobile-sheet hidden aria-label="Mehr">
|
<nav class="mobile-nav-extension" data-mobile-sheet hidden aria-label="Mehr Navigation">
|
||||||
<div class="mobile-sheet-head">
|
<a class="mobile-extra-link" href="{{ url_for('main.item_list', kind='food') }}"><span class="ui-icon icon-utensils"></span><span>Lebensmittel</span></a>
|
||||||
<div>
|
<a class="mobile-extra-link" href="{{ url_for('main.item_list', kind='meal') }}"><span class="ui-icon icon-bowl-food"></span><span>Mahlzeiten</span></a>
|
||||||
<strong>{{ g.user.display_name or g.user.username }}</strong>
|
<a class="mobile-extra-link" href="{{ url_for('main.home_view') }}"><span class="ui-icon icon-house"></span><span>Zuhause</span></a>
|
||||||
<small>{{ role_labels[g.user.role] }}</small>
|
<a class="mobile-extra-link" href="{{ url_for('main.archive_view') }}"><span class="ui-icon icon-archive"></span><span>Archiv</span></a>
|
||||||
</div>
|
<a class="mobile-extra-link" href="{{ url_for('main.template_library') }}"><span class="ui-icon icon-leaf"></span><span>Vorlagen</span></a>
|
||||||
<button class="ghost-button" type="button" data-mobile-sheet-close>Schließen</button>
|
<a class="mobile-extra-link" href="{{ url_for('main.settings_view') }}"><span class="ui-icon icon-sliders"></span><span>Optionen</span></a>
|
||||||
</div>
|
<a class="mobile-extra-link" href="{{ url_for('auth.profile') }}"><span class="ui-icon icon-heart"></span><span>Profil</span></a>
|
||||||
<nav class="mobile-sheet-links card-link-grid">
|
|
||||||
<a class="menu-card" href="{{ url_for('main.item_list', kind='food') }}"><span class="ui-icon icon-utensils"></span><span>Lebensmittel</span></a>
|
|
||||||
<a class="menu-card" href="{{ url_for('main.item_list', kind='meal') }}"><span class="ui-icon icon-bowl-food"></span><span>Mahlzeiten</span></a>
|
|
||||||
<a class="menu-card" href="{{ url_for('main.home_view') }}"><span class="ui-icon icon-house"></span><span>Zuhause</span></a>
|
|
||||||
<a class="menu-card" href="{{ url_for('main.archive_view') }}"><span class="ui-icon icon-archive"></span><span>Archiv</span></a>
|
|
||||||
<a class="menu-card" href="{{ url_for('main.template_library') }}"><span class="ui-icon icon-leaf"></span><span>Vorlagen</span></a>
|
|
||||||
<a class="menu-card" href="{{ url_for('main.settings_view') }}"><span class="ui-icon icon-sliders"></span><span>Optionen</span></a>
|
|
||||||
<a class="menu-card" href="{{ url_for('auth.profile') }}"><span class="ui-icon icon-heart"></span><span>Profil</span></a>
|
|
||||||
{% if g.user.role == 'admin' %}
|
{% if g.user.role == 'admin' %}
|
||||||
<a class="menu-card" href="{{ url_for('admin.user_list') }}"><span class="ui-icon icon-sparkles"></span><span>Nutzer</span></a>
|
<a class="mobile-extra-link" href="{{ url_for('admin.user_list') }}"><span class="ui-icon icon-sparkles"></span><span>Nutzer</span></a>
|
||||||
<a class="menu-card" href="{{ url_for('admin.category_settings') }}"><span class="ui-icon icon-seedling"></span><span>Kategorien</span></a>
|
<a class="mobile-extra-link" href="{{ url_for('admin.category_settings') }}"><span class="ui-icon icon-seedling"></span><span>Kategorien</span></a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</nav>
|
<button class="mobile-extra-link mobile-extra-button" type="button" data-theme-toggle>
|
||||||
<div class="mobile-sheet-actions">
|
<span class="ui-icon icon-mobile-screen-button"></span>
|
||||||
<button class="ghost-button" type="button" data-theme-toggle>Modus wechseln</button>
|
<span>Modus</span>
|
||||||
<form method="post" action="{{ url_for('auth.logout') }}">
|
</button>
|
||||||
|
<form method="post" action="{{ url_for('auth.logout') }}" class="mobile-extra-form">
|
||||||
{{ csrf_input() }}
|
{{ csrf_input() }}
|
||||||
<button class="ghost-button" type="submit">Abmelden</button>
|
<button class="mobile-extra-link mobile-extra-button" type="submit">
|
||||||
|
<span class="ui-icon icon-ellipsis"></span>
|
||||||
|
<span>Abmelden</span>
|
||||||
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</nav>
|
||||||
</aside>
|
|
||||||
|
|
||||||
<nav class="mobile-bottom-nav" aria-label="Mobile Navigation">
|
<nav class="mobile-bottom-nav" aria-label="Mobile Navigation">
|
||||||
<a href="{{ url_for('main.dashboard') }}" class="{{ 'active' if request.endpoint == 'main.dashboard' else '' }}">
|
<a href="{{ url_for('main.dashboard') }}" class="{{ 'active' if request.endpoint == 'main.dashboard' else '' }}">
|
||||||
@@ -146,6 +141,7 @@
|
|||||||
<span>Mehr</span>
|
<span>Mehr</span>
|
||||||
</button>
|
</button>
|
||||||
</nav>
|
</nav>
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
#!/bin/sh
|
#!/bin/bash
|
||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
export NOURI_DATA_DIR="${NOURI_DATA_DIR:-/app/data}"
|
mkdir -p /app/data/uploads
|
||||||
mkdir -p "${NOURI_DATA_DIR}"
|
|
||||||
mkdir -p "${NOURI_DATA_DIR}/uploads"
|
|
||||||
|
|
||||||
exec gunicorn \
|
# Vorhandene lokale SQLite-Datei beim allerersten Start übernehmen
|
||||||
--bind 0.0.0.0:8000 \
|
if [ ! -f /app/data/nouri.sqlite3 ] && [ -f /app/bootstrap-data/nouri.sqlite3 ]; then
|
||||||
--workers 2 \
|
cp /app/bootstrap-data/nouri.sqlite3 /app/data/nouri.sqlite3
|
||||||
--threads 4 \
|
fi
|
||||||
--timeout 60 \
|
|
||||||
wsgi:app
|
# Vorhandene Uploads beim allerersten Start übernehmen
|
||||||
|
if [ -d /app/bootstrap-data/uploads ] && [ -z "$(ls -A /app/data/uploads 2>/dev/null || true)" ]; then
|
||||||
|
cp -a /app/bootstrap-data/uploads/. /app/data/uploads/
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec gunicorn --bind 0.0.0.0:8000 --workers 2 --threads 4 wsgi:app
|
||||||
Reference in New Issue
Block a user