diff --git a/events/templates/events/event_detail.html b/events/templates/events/event_detail.html
index 1861fe2..7feb6db 100644
--- a/events/templates/events/event_detail.html
+++ b/events/templates/events/event_detail.html
@@ -38,11 +38,12 @@
-
+
{{ frame.filename }} in {{ frame.function }} line {{ frame.lineno }}.
-
{# todo this still shows the last frame of non-last exceptions, I just want the very last one #}
+
{# todo the if-statements on forloop.last still show the last frame of non-last exceptions, I just want the very last one #}
{% for line in frame.pre_context %}{{ line }} {# leave space to avoid collapse #}
{% endfor %}
diff --git a/static/js/issue.js b/static/js/issue.js
index 61abd02..7c7788a 100644
--- a/static/js/issue.js
+++ b/static/js/issue.js
@@ -1,39 +1,94 @@
"use strict";
+// This is the important part!
+function collapseSection(element) {
+ if (element.getAttribute("data-collapsed") === "true") {
+ return;
+ }
+
+ element.classList.remove("xl:flex"); // this appears to be necessary, not sure why
+
+ // get the height of the element's inner content, regardless of its actual size
+ var sectionHeight = element.scrollHeight;
+
+ // temporarily disable all css transitions
+ var elementTransition = element.style.transition;
+ element.style.transition = '';
+
+ // on the next frame (as soon as the previous style change has taken effect),
+ // explicitly set the element's height to its current pixel height, so we
+ // aren't transitioning out of 'auto'
+ requestAnimationFrame(function() {
+ element.style.height = sectionHeight + 'px';
+ element.style.transition = elementTransition;
+
+ // on the next frame (as soon as the previous style change has taken effect),
+ // have the element transition to height: 0
+ requestAnimationFrame(function() {
+ element.style.height = 0 + 'px';
+ });
+ });
+
+ // mark the section as "currently collapsed"
+ element.setAttribute('data-collapsed', 'true');
+}
+
+function expandSection(element) {
+ if (element.getAttribute("data-collapsed") !== "true") {
+ return;
+ }
+
+ element.classList.add("xl:flex"); // add back
+
+ // get the height of the element's inner content, regardless of its actual size
+ var sectionHeight = element.scrollHeight;
+
+ // have the element transition to the height of its inner content
+ element.style.height = sectionHeight + 'px';
+
+ // when the next css transition finishes (which should be the one we just triggered)
+ const foo = function(e) {
+ // remove this event listener so it only gets triggered once
+ element.removeEventListener('transitionend', foo);
+
+ // remove "height" from the element's inline styles, so it can return to its initial value
+ element.style.removeProperty("height");
+ }
+
+ element.addEventListener('transitionend', foo);
+
+ // mark the section as "currently not collapsed"
+ element.setAttribute('data-collapsed', 'false');
+}
+
function toggleFrameVisibility(frameHeader) {
const frameDetails = frameHeader.parentNode.querySelector(".js-frame-details");
- if (frameDetails.classList.contains("hidden")) {
- frameDetails.classList.remove("hidden");
- frameDetails.classList.add("xl:flex"); // add back
+ if (frameDetails.getAttribute("data-collapsed") === "true") {
+ expandSection(frameDetails);
} else {
- frameDetails.classList.add("hidden");
- frameDetails.classList.remove("xl:flex"); // this appears to be necessary, not sure why
+ collapseSection(frameDetails);
}
}
function showAllFrames(frameHeader) {
document.querySelectorAll(".js-frame-details").forEach((frameDetails) => {
- frameDetails.classList.remove("hidden");
- frameDetails.classList.add("xl:flex");
+ expandSection(frameDetails);
});
}
function showInAppFrames(frameHeader) {
document.querySelectorAll(".js-frame-details").forEach((frameDetails) => {
if (frameDetails.classList.contains("js-in-app")) {
- frameDetails.classList.remove("hidden");
- frameDetails.classList.add("xl:flex"); // add back
+ expandSection(frameDetails);
} else {
- frameDetails.classList.add("hidden");
- frameDetails.classList.remove("xl:flex"); // this appears to be necessary, not sure why
+ collapseSection(frameDetails);
}
});
}
function hideAllFrames(frameHeader) {
document.querySelectorAll(".js-frame-details").forEach((frameDetails) => {
- frameDetails.classList.add("hidden");
- frameDetails.classList.remove("xl:flex"); // this appears to be necessary, not sure why
+ collapseSection(frameDetails);
});
}
diff --git a/theme/static/css/dist/styles.css b/theme/static/css/dist/styles.css
index 15235a7..d3ebc4c 100644
--- a/theme/static/css/dist/styles.css
+++ b/theme/static/css/dist/styles.css
@@ -876,6 +876,14 @@ select {
height: 100vh;
}
+.h-0 {
+ height: 0px;
+}
+
+.max-h-0 {
+ max-height: 0px;
+}
+
.w-1\/4 {
width: 25%;
}
@@ -932,6 +940,10 @@ select {
justify-items: end;
}
+.overflow-hidden {
+ overflow: hidden;
+}
+
.whitespace-pre {
white-space: pre;
}
@@ -1193,6 +1205,24 @@ select {
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
}
+.transition-all {
+ transition-property: all;
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
+ transition-duration: 150ms;
+}
+
+.delay-150 {
+ transition-delay: 150ms;
+}
+
+.delay-1000 {
+ transition-delay: 1000ms;
+}
+
+.duration-1000 {
+ transition-duration: 1000ms;
+}
+
.ease-in-out {
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}