Full Printing Now Available (with some bugs) #20

Merged
connor merged 9 commits from print-preview-feature into main 2025-09-12 14:56:42 -04:00
2 changed files with 90 additions and 21 deletions
Showing only changes of commit 64dbf65beb - Show all commits

View File

@@ -1128,7 +1128,7 @@
.print-preview-paper[data-start-hour="7"][data-end-hour="19"]:has(.time-slot.quarter-mode) .time-labels,
.print-preview-paper[data-start-hour="7"][data-end-hour="19"]:has(.time-slot.quarter-mode) .week-days-grid { min-height: 1530px !important; }
/* Print Page Setup - Force landscape orientation */
/* Print Page Setup - Force landscape orientation and fit to page */
@page {
size: landscape;
margin: 0.5in;
@@ -1136,6 +1136,11 @@
/* Print Media Rules - Show only the print-preview-copy when printing */
@media print {
html {
print-color-adjust: exact; /* Preserve colors when printing */
-webkit-print-color-adjust: exact;
}
/* Hide all top-level app content */
.app {
display: none !important;
@@ -1147,11 +1152,19 @@
position: absolute !important;
left: 0 !important;
top: 0 !important;
width: 960px !important;
height: 720px !important;
/* width: 960px !important; */
/* height: 720px !important; */
aspect-ratio: 1.2941176470588236 !important;
margin: 0 !important;
padding: 0 !important;
box-sizing: border-box !important;
/* Properties to help browsers scale to fit page */
max-width: 100vw;
max-height: 100vh;
object-fit: contain;
page-break-inside: avoid;
orphans: 1;
widows: 1;
}
/* Ensure print content uses the full page */

View File

@@ -106,8 +106,8 @@ pub fn PrintPreviewModal(props: &PrintPreviewModalProps) -> Html {
{
let start_hour = *start_hour;
let end_hour = *end_hour;
let base_unit_value = base_unit;
let pixels_per_hour_value = pixels_per_hour;
let time_increment = props.time_increment;
let original_base_unit = base_unit;
use_effect(move || {
if let Some(window) = web_sys::window() {
if let Some(document) = window.document() {
@@ -115,8 +115,6 @@ pub fn PrintPreviewModal(props: &PrintPreviewModalProps) -> Html {
if let Some(document_element) = document.document_element() {
if let Some(html_element) = document_element.dyn_ref::<web_sys::HtmlElement>() {
let style = html_element.style();
let _ = style.set_property("--print-base-unit", &format!("{:.2}", base_unit_value));
let _ = style.set_property("--print-pixels-per-hour", &format!("{:.2}", pixels_per_hour_value));
let _ = style.set_property("--print-start-hour", &start_hour.to_string());
let _ = style.set_property("--print-end-hour", &end_hour.to_string());
}
@@ -132,22 +130,80 @@ pub fn PrintPreviewModal(props: &PrintPreviewModalProps) -> Html {
print_copy.set_inner_html("");
let _ = print_copy.append_child(&content_clone);
// Copy the CSS variables and data attributes from the print-preview-paper
if let Some(preview_paper) = document.query_selector(".print-preview-paper").ok().flatten() {
if let Some(_paper_element) = preview_paper.dyn_ref::<web_sys::HtmlElement>() {
// Copy CSS custom properties (variables)
if let Some(print_copy_html) = print_copy.dyn_ref::<web_sys::HtmlElement>() {
let style = print_copy_html.style();
let _ = style.set_property("--print-start-hour", &start_hour.to_string());
let _ = style.set_property("--print-end-hour", &end_hour.to_string());
let _ = style.set_property("--print-base-unit", &format!("{:.2}", base_unit_value));
let _ = style.set_property("--print-pixels-per-hour", &format!("{:.2}", pixels_per_hour_value));
// Get the actual rendered height of the print copy div and recalculate base-unit
if let Some(print_copy_html) = print_copy.dyn_ref::<web_sys::HtmlElement>() {
// Temporarily make visible to measure height, then hide again
let original_display = print_copy_html.style().get_property_value("display").unwrap_or_default();
let _ = print_copy_html.style().set_property("display", "block");
let _ = print_copy_html.style().set_property("visibility", "hidden");
let _ = print_copy_html.style().set_property("position", "absolute");
let _ = print_copy_html.style().set_property("top", "-9999px");
// Now measure the height
let actual_height = print_copy_html.client_height() as f64;
// Restore original display
let _ = print_copy_html.style().set_property("display", &original_display);
let _ = print_copy_html.style().remove_property("visibility");
let _ = print_copy_html.style().remove_property("position");
let _ = print_copy_html.style().remove_property("top");
// Recalculate base-unit and pixels-per-hour based on actual height
let visible_hours = (end_hour - start_hour) as f64;
let slots_per_hour = if time_increment == 15 { 4.0 } else { 2.0 };
let header_height = 50.0;
let header_border = 2.0;
let container_spacing = 8.0;
let total_overhead = header_height + header_border + container_spacing;
let available_height = actual_height - total_overhead;
let actual_base_unit = available_height / (visible_hours * slots_per_hour);
let actual_pixels_per_hour = actual_base_unit * slots_per_hour;
// Set CSS variables with recalculated values
let style = print_copy_html.style();
let _ = style.set_property("--print-base-unit", &format!("{:.2}", actual_base_unit));
let _ = style.set_property("--print-pixels-per-hour", &format!("{:.2}", actual_pixels_per_hour));
let _ = style.set_property("--print-start-hour", &start_hour.to_string());
let _ = style.set_property("--print-end-hour", &end_hour.to_string());
// Copy data attributes
let _ = print_copy.set_attribute("data-start-hour", &start_hour.to_string());
let _ = print_copy.set_attribute("data-end-hour", &end_hour.to_string());
// Recalculate event positions using the new base-unit
let events = print_copy.query_selector_all(".week-event").unwrap();
let scale_factor = actual_base_unit / original_base_unit;
for i in 0..events.length() {
if let Some(event_element) = events.get(i) {
if let Some(event_html) = event_element.dyn_ref::<web_sys::HtmlElement>() {
let event_style = event_html.style();
// Get current positioning values and recalculate
if let Ok(current_top) = event_style.get_property_value("top") {
if current_top.ends_with("px") {
if let Ok(top_px) = current_top[..current_top.len()-2].parse::<f64>() {
let new_top = top_px * scale_factor;
let _ = event_style.set_property("top", &format!("{:.2}px", new_top));
}
}
}
if let Ok(current_height) = event_style.get_property_value("height") {
if current_height.ends_with("px") {
if let Ok(height_px) = current_height[..current_height.len()-2].parse::<f64>() {
let new_height = height_px * scale_factor;
let _ = event_style.set_property("height", &format!("{:.2}px", new_height));
}
}
}
}
}
// Copy data attributes
let _ = print_copy.set_attribute("data-start-hour", &start_hour.to_string());
let _ = print_copy.set_attribute("data-end-hour", &end_hour.to_string());
}
web_sys::console::log_1(&format!("Height: {:.2}, Original base-unit: {:.2}, New base-unit: {:.2}, Scale factor: {:.2}",
actual_height, original_base_unit, actual_base_unit, scale_factor).into());
}
}
}