Comparison History
-
Recent comparison results (last {{ comparison_data.history|length }} checks)
+
Recent comparison results (last {{ comparison_data.history|length }} checks)
@@ -314,9 +144,9 @@
| {{ entry.method }} |
{% if entry.changed %}
- Yes
+ Yes
{% else %}
- No
+ No
{% endif %}
|
@@ -363,6 +193,42 @@ function downloadImage(imageId, filename) {
URL.revokeObjectURL(url);
}, 100);
}
+
+/**
+ * Synchronize comparison slider width with diff image width
+ * This ensures both panels display images at the same max-width
+ */
+function syncComparisonWidth() {
+ const diffImage = document.getElementById('diff-image');
+ const comparisonContainer = document.getElementById('comparison-container');
+
+ if (!diffImage || !comparisonContainer) return;
+
+ // Wait for diff image to load to get its actual rendered width
+ if (diffImage.complete) {
+ applyWidth();
+ } else {
+ diffImage.addEventListener('load', applyWidth);
+ }
+
+ function applyWidth() {
+ const diffImageWidth = diffImage.offsetWidth;
+ if (diffImageWidth > 0) {
+ comparisonContainer.style.maxWidth = diffImageWidth + 'px';
+ comparisonContainer.style.margin = '0 auto';
+ }
+ }
+}
+
+// Run on page load
+if (document.readyState === 'loading') {
+ document.addEventListener('DOMContentLoaded', syncComparisonWidth);
+} else {
+ syncComparisonWidth();
+}
+
+// Re-sync on window resize
+window.addEventListener('resize', syncComparisonWidth);
diff --git a/changedetectionio/static/styles/scss/diff-image.scss b/changedetectionio/static/styles/scss/diff-image.scss
new file mode 100644
index 00000000..35c05201
--- /dev/null
+++ b/changedetectionio/static/styles/scss/diff-image.scss
@@ -0,0 +1,259 @@
+/**
+ * Image Comparison Diff Styles
+ * Styles for the interactive image comparison slider and screenshot diff visualization
+ */
+
+.comparison-score {
+ padding: 1em;
+ background: var(--color-table-stripe);
+ border-radius: 4px;
+ margin: 1em 0;
+ border: 1px solid var(--color-border-table-cell);
+ color: var(--color-text);
+}
+
+.change-detected {
+ color: #d32f2f;
+ font-weight: bold;
+}
+
+.no-change {
+ color: #388e3c;
+ font-weight: bold;
+}
+
+.comparison-grid {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 1em;
+ margin: 1em 1em;
+
+ @media (max-width: 1200px) {
+ grid-template-columns: 1fr;
+ }
+}
+
+/* Interactive Image Comparison Slider */
+.image-comparison {
+ position: relative;
+ width: 100%;
+ overflow: hidden;
+ border: 1px solid var(--color-border-table-cell);
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+ user-select: none;
+
+ img {
+ display: block;
+ width: 100%;
+ height: auto;
+ max-width: 100%;
+ border: none;
+ box-shadow: none;
+ }
+}
+
+/* Image wrappers with checkered background */
+.comparison-image-wrapper {
+ position: relative;
+ width: 100%;
+ display: flex;
+ align-items: flex-start;
+ justify-content: center;
+ /* Very light checkered background pattern */
+ background-color: var(--color-background);
+ background-image:
+ linear-gradient(45deg, var(--color-table-stripe) 25%, transparent 25%),
+ linear-gradient(-45deg, var(--color-table-stripe) 25%, transparent 25%),
+ linear-gradient(45deg, transparent 75%, var(--color-table-stripe) 75%),
+ linear-gradient(-45deg, transparent 75%, var(--color-table-stripe) 75%);
+ background-size: 20px 20px;
+ background-position: 0 0, 0 10px, 10px -10px, -10px 0px;
+}
+
+.comparison-after {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ clip-path: inset(0 0 0 50%);
+}
+
+.comparison-slider {
+ position: absolute;
+ top: 0;
+ left: 50%;
+ width: 4px;
+ height: 100%;
+ background: #0078e7;
+ cursor: ew-resize;
+ transform: translateX(-2px);
+ z-index: 10;
+}
+
+.comparison-handle {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ width: 48px;
+ height: 48px;
+ background: #0078e7;
+ border: 3px solid white;
+ border-radius: 50%;
+ transform: translate(-50%, -50%);
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ cursor: ew-resize;
+ transition: top 0.1s ease-out;
+
+ &::after {
+ content: '⇄';
+ color: white;
+ font-size: 24px;
+ font-weight: bold;
+ pointer-events: none;
+ }
+}
+
+.comparison-labels {
+ position: absolute;
+ top: 10px;
+ width: 100%;
+ display: flex;
+ justify-content: space-between;
+ padding: 0 0px;
+ z-index: 5;
+ pointer-events: none;
+}
+
+.comparison-label {
+ background: rgba(0, 0, 0, 0.7);
+ color: white;
+ padding: 0.5em 1em;
+ border-radius: 4px;
+ font-size: 0.9em;
+ font-weight: bold;
+}
+
+.screenshot-panel {
+ text-align: center;
+ background: var(--color-background);
+ border: 1px solid var(--color-border-table-cell);
+ border-radius: 4px;
+ padding: 1em;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
+
+ h3 {
+ margin: 0 0 1em 0;
+ font-size: 1.1em;
+ color: var(--color-text);
+ border-bottom: 2px solid var(--color-background-button-primary);
+ padding-bottom: 0.5em;
+ }
+
+ &.diff h3 {
+ border-bottom-color: #d32f2f;
+ }
+
+ img {
+ max-width: 100%;
+ height: auto;
+ border: 1px solid var(--color-border-table-cell);
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+ }
+}
+
+.version-selector {
+ display: inline-block;
+ margin: 0 0.5em;
+
+ label {
+ font-weight: bold;
+ margin-right: 0.5em;
+ color: var(--color-text);
+ }
+}
+
+#settings {
+ background: var(--color-background);
+ padding: 1.5em;
+ border-radius: 4px;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
+ margin-bottom: 2em;
+ border: 1px solid var(--color-border-table-cell);
+
+ h2 {
+ margin-top: 0;
+ color: var(--color-text);
+ }
+}
+
+.diff-fieldset {
+ border: none;
+ padding: 0;
+ margin: 0;
+}
+
+.edit-link {
+ float: right;
+ margin-top: -0.5em;
+}
+
+.comparison-description {
+ color: var(--color-text-input-description);
+ font-size: 0.9em;
+ margin-bottom: 1em;
+}
+
+.download-link {
+ color: var(--color-link);
+ text-decoration: none;
+ display: inline-flex;
+ align-items: center;
+ gap: 0.3em;
+ font-size: 0.85em;
+
+ &:hover {
+ text-decoration: underline;
+ }
+}
+
+.diff-section-header {
+ color: #d32f2f;
+ font-size: 0.9em;
+ margin-bottom: 1em;
+ font-weight: bold;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 1em;
+}
+
+.comparison-history-section {
+ margin-top: 3em;
+ padding: 1em;
+ background: var(--color-background);
+ border: 1px solid var(--color-border-table-cell);
+ border-radius: 4px;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
+
+ h3 {
+ color: var(--color-text);
+ }
+
+ p {
+ color: var(--color-text-input-description);
+ font-size: 0.9em;
+ }
+}
+
+.history-changed-yes {
+ color: #d32f2f;
+ font-weight: bold;
+}
+
+.history-changed-no {
+ color: #388e3c;
+}