hoi
This commit is contained in:
87
backend/static/dashboard-transition.js
Normal file
87
backend/static/dashboard-transition.js
Normal file
@@ -0,0 +1,87 @@
|
||||
(() => {
|
||||
const OPENING_MS = 420;
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
const dashboardGrid = document.querySelector(".dashboard-grid");
|
||||
const dashboardLinks = document.querySelectorAll(".dashboard-link-card[href]");
|
||||
|
||||
if (dashboardGrid) {
|
||||
dashboardLinks.forEach((link, index) => {
|
||||
link.style.setProperty("--stagger-delay", `${index * 55}ms`);
|
||||
});
|
||||
|
||||
dashboardGrid.classList.add("is-ready");
|
||||
window.requestAnimationFrame(() => {
|
||||
dashboardGrid.classList.add("is-animated");
|
||||
});
|
||||
}
|
||||
|
||||
dashboardLinks.forEach((link) => {
|
||||
link.addEventListener("click", (event) => {
|
||||
if (link.classList.contains("is-opening")) {
|
||||
event.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
event.defaultPrevented ||
|
||||
event.button !== 0 ||
|
||||
event.metaKey ||
|
||||
event.ctrlKey ||
|
||||
event.shiftKey ||
|
||||
event.altKey
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const href = link.getAttribute("href");
|
||||
if (!href || href.startsWith("http")) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
if (dashboardGrid) {
|
||||
dashboardGrid.classList.add("is-focusing");
|
||||
}
|
||||
link.classList.add("is-opening");
|
||||
|
||||
// Force layout before running the exit animation for consistent playback.
|
||||
void link.offsetWidth;
|
||||
|
||||
let hasNavigated = false;
|
||||
const navigate = () => {
|
||||
if (hasNavigated) {
|
||||
return;
|
||||
}
|
||||
hasNavigated = true;
|
||||
window.location.href = href;
|
||||
};
|
||||
|
||||
if (typeof link.animate === "function") {
|
||||
const animation = link.animate(
|
||||
[
|
||||
{ opacity: 1, transform: "translateY(-6px) scale(1)", filter: "blur(0px)" },
|
||||
{ opacity: 0, transform: "translateY(-42px) scale(0.982)", filter: "blur(2px)" },
|
||||
],
|
||||
{
|
||||
duration: OPENING_MS,
|
||||
easing: "cubic-bezier(0.22, 0.61, 0.36, 1)",
|
||||
fill: "forwards",
|
||||
}
|
||||
);
|
||||
animation.finished.then(navigate).catch(navigate);
|
||||
} else {
|
||||
// Fallback if WAAPI is unavailable.
|
||||
link.style.transition = `transform ${OPENING_MS}ms cubic-bezier(0.22, 0.61, 0.36, 1), opacity ${OPENING_MS}ms cubic-bezier(0.22, 0.61, 0.36, 1), filter ${OPENING_MS}ms cubic-bezier(0.22, 0.61, 0.36, 1)`;
|
||||
requestAnimationFrame(() => {
|
||||
link.style.transform = "translateY(-42px) scale(0.982)";
|
||||
link.style.opacity = "0";
|
||||
link.style.filter = "blur(2px)";
|
||||
});
|
||||
}
|
||||
|
||||
window.setTimeout(navigate, OPENING_MS + 240);
|
||||
});
|
||||
});
|
||||
});
|
||||
})();
|
||||
@@ -130,11 +130,73 @@ h3 {
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||
}
|
||||
|
||||
.dashboard-grid {
|
||||
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.dashboard-grid.is-ready .dashboard-link-card {
|
||||
opacity: 0;
|
||||
transform: translateY(14px) scale(0.985);
|
||||
}
|
||||
|
||||
.dashboard-grid.is-ready.is-animated .dashboard-link-card {
|
||||
animation: dashboard-card-in 460ms cubic-bezier(0.22, 0.61, 0.36, 1) both;
|
||||
animation-delay: var(--stagger-delay, 0ms);
|
||||
}
|
||||
|
||||
.dashboard-grid.is-focusing .dashboard-link-card:not(.is-opening) {
|
||||
opacity: 0.56;
|
||||
transform: scale(0.975);
|
||||
filter: saturate(0.82);
|
||||
}
|
||||
|
||||
@keyframes dashboard-card-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(14px) scale(0.985);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0) scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
.dashboard-link-card {
|
||||
min-height: 140px;
|
||||
aspect-ratio: 1 / 1;
|
||||
font-size: 1.14rem;
|
||||
font-weight: 600;
|
||||
border-radius: 20px;
|
||||
padding: 1rem;
|
||||
position: relative;
|
||||
background: #fffdf9;
|
||||
border: 1px solid rgba(39, 66, 53, 0.11);
|
||||
letter-spacing: 0.01em;
|
||||
box-shadow: 0 12px 30px rgba(39, 66, 53, 0.12);
|
||||
will-change: transform, opacity, filter;
|
||||
}
|
||||
|
||||
.dashboard-link-card:hover {
|
||||
transform: translateY(-6px);
|
||||
box-shadow: 0 18px 40px rgba(39, 66, 53, 0.18);
|
||||
}
|
||||
|
||||
.dashboard-link-card.is-opening {
|
||||
box-shadow: 0 20px 44px rgba(39, 66, 53, 0.22);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.link-card:hover {
|
||||
transform: translateY(-3px);
|
||||
box-shadow: 0 14px 30px rgba(39, 66, 53, 0.16);
|
||||
}
|
||||
|
||||
.dashboard-grid .dashboard-link-card:hover {
|
||||
transform: translateY(-6px);
|
||||
box-shadow: 0 18px 40px rgba(39, 66, 53, 0.18);
|
||||
}
|
||||
|
||||
.form-card {
|
||||
max-width: 560px;
|
||||
}
|
||||
@@ -721,6 +783,26 @@ input[type="file"]:focus {
|
||||
.location-actions {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.dashboard-grid {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.dashboard-link-card {
|
||||
min-height: 0;
|
||||
font-size: 1.08rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 380px) {
|
||||
.dashboard-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.dashboard-link-card {
|
||||
min-height: 118px;
|
||||
aspect-ratio: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.site-footer {
|
||||
|
||||
@@ -51,5 +51,6 @@
|
||||
<a href="{{ url_for('datenschutz') }}">{{ t('privacy') }}</a>
|
||||
<a href="{{ url_for('impressum') }}">{{ t('imprint') }}</a>
|
||||
</footer>
|
||||
<script src="{{ url_for('static', filename='dashboard-transition.js', v='20260302c') }}" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -5,16 +5,16 @@
|
||||
<p>{{ t('hello_guest').format(name=guest_name) }}</p>
|
||||
</section>
|
||||
|
||||
<section class="card-grid">
|
||||
<a class="card link-card" href="{{ url_for('rsvp') }}">{{ t('rsvp') }}</a>
|
||||
<a class="card link-card" href="{{ url_for('upload') }}">{{ t('upload') }}</a>
|
||||
<a class="card link-card" href="{{ url_for('gallery') }}">{{ t('gallery') }}</a>
|
||||
<a class="card link-card" href="{{ url_for('info', page='schedule') }}">{{ t('schedule') }}</a>
|
||||
<a class="card link-card" href="{{ url_for('info', page='hotels') }}">{{ t('hotels') }}</a>
|
||||
<a class="card link-card" href="{{ url_for('info', page='taxi') }}">{{ t('taxi') }}</a>
|
||||
<a class="card link-card" href="{{ url_for('info', page='location') }}">{{ t('location') }}</a>
|
||||
<section class="card-grid dashboard-grid">
|
||||
<a class="card link-card dashboard-link-card" href="{{ url_for('rsvp') }}">{{ t('rsvp') }}</a>
|
||||
<a class="card link-card dashboard-link-card" href="{{ url_for('upload') }}">{{ t('upload') }}</a>
|
||||
<a class="card link-card dashboard-link-card" href="{{ url_for('gallery') }}">{{ t('gallery') }}</a>
|
||||
<a class="card link-card dashboard-link-card" href="{{ url_for('info', page='schedule') }}">{{ t('schedule') }}</a>
|
||||
<a class="card link-card dashboard-link-card" href="{{ url_for('info', page='hotels') }}">{{ t('hotels') }}</a>
|
||||
<a class="card link-card dashboard-link-card" href="{{ url_for('info', page='taxi') }}">{{ t('taxi') }}</a>
|
||||
<a class="card link-card dashboard-link-card" href="{{ url_for('info', page='location') }}">{{ t('location') }}</a>
|
||||
{% if is_admin %}
|
||||
<a class="card link-card" href="{{ url_for('host_area') }}">{{ t('host_area') }}</a>
|
||||
<a class="card link-card dashboard-link-card" href="{{ url_for('host_area') }}">{{ t('host_area') }}</a>
|
||||
{% endif %}
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user