mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-07-25 22:55:22 +00:00
Scaling fixes (#3868)
# Description of Changes Please provide a summary of the changes, including: - What was changed - Why the change was made - Any challenges encountered Closes #(issue_number) --- ## Checklist ### General - [ ] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [ ] I have read the [Stirling-PDF Developer Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md) (if applicable) - [ ] I have read the [How to add new languages to Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md) (if applicable) - [ ] I have performed a self-review of my own code - [ ] My changes generate no new warnings ### Documentation - [ ] I have updated relevant docs on [Stirling-PDF's doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/) (if functionality has heavily changed) - [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only) ### UI Changes (if applicable) - [ ] Screenshots or videos demonstrating the UI changes are attached (e.g., as comments or direct attachments in the PR) ### Testing (if applicable) - [ ] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#6-testing) for more details. --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
parent
6158454020
commit
0a402e562b
@ -16,9 +16,8 @@
|
|||||||
|
|
||||||
.navbar {
|
.navbar {
|
||||||
height: auto;
|
height: auto;
|
||||||
/* Adjusts height automatically based on content */
|
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
/* Prevents wrapping of navbar contents */
|
width: 100vw;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO enable later
|
/* TODO enable later
|
||||||
@ -30,6 +29,7 @@
|
|||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
|
|
||||||
html[dir="ltr"] * {
|
html[dir="ltr"] * {
|
||||||
direction: ltr;
|
direction: ltr;
|
||||||
}
|
}
|
||||||
|
@ -269,7 +269,9 @@ span.icon-text::after {
|
|||||||
|
|
||||||
/* Mega Menu */
|
/* Mega Menu */
|
||||||
.dropdown-mega .dropdown-menu {
|
.dropdown-mega .dropdown-menu {
|
||||||
width: 98%;
|
width: 100%;
|
||||||
|
left: 0 !important;
|
||||||
|
right: auto !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropdown-mega .title {
|
.dropdown-mega .title {
|
||||||
@ -477,9 +479,8 @@ html[dir="rtl"] .dropdown-menu[data-bs-popper] {
|
|||||||
display: flex;
|
display: flex;
|
||||||
gap: 30px;
|
gap: 30px;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
width: 140%;
|
width: 100%;
|
||||||
position: relative;
|
position: relative;
|
||||||
left: -20%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.feature-group {
|
.feature-group {
|
||||||
|
@ -23,6 +23,87 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
window.stirlingPDF = window.stirlingPDF || {};
|
window.stirlingPDF = window.stirlingPDF || {};
|
||||||
|
|
||||||
|
// Capture true system DPI at page load (before any zoom interactions)
|
||||||
|
const systemDPR = window.devicePixelRatio || 1;
|
||||||
|
|
||||||
|
// Determine if this is actually a high DPI screen at page load
|
||||||
|
const isHighDPI = systemDPR > 1.4;
|
||||||
|
|
||||||
|
function scaleNav() {
|
||||||
|
const currentDPR = window.devicePixelRatio || 1;
|
||||||
|
const browserZoom = currentDPR / systemDPR;
|
||||||
|
|
||||||
|
// Counter-scale to maintain same visual size
|
||||||
|
const isMobile = window.innerWidth <= 768 || /Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
|
||||||
|
let baseScale = isMobile ? 3 : (isHighDPI ? 2.2 : 1.1); // Prioritize mobile scaling over high DPI
|
||||||
|
const navScale = baseScale / currentDPR;
|
||||||
|
// Dropdowns at 80% (20% smaller)
|
||||||
|
const dropdownScale = 0.8;
|
||||||
|
|
||||||
|
|
||||||
|
const navbar = document.querySelector('.navbar');
|
||||||
|
|
||||||
|
if (navbar) {
|
||||||
|
// RTL support - check document direction
|
||||||
|
const isRTL = document.documentElement.dir === 'rtl' || document.documentElement.getAttribute('dir') === 'rtl';
|
||||||
|
|
||||||
|
const translateX = isRTL ? '50%' : '-50%';
|
||||||
|
navbar.style.transform = `translateX(${translateX}) scale(${navScale})`;
|
||||||
|
navbar.style.transformOrigin = 'top center';
|
||||||
|
navbar.style.width = `${100 / navScale}%`;
|
||||||
|
|
||||||
|
if (isRTL) {
|
||||||
|
navbar.style.right = '50%';
|
||||||
|
navbar.style.left = 'auto';
|
||||||
|
} else {
|
||||||
|
navbar.style.left = '50%';
|
||||||
|
navbar.style.right = 'auto';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adjust bottom margin based on scale to prevent overlap/gaps
|
||||||
|
const baseHeight = 60; // Assume base navbar height
|
||||||
|
const scaledHeight = baseHeight * navScale;
|
||||||
|
const marginAdjustment = scaledHeight - baseHeight;
|
||||||
|
navbar.style.marginBottom = `${marginAdjustment}px`;
|
||||||
|
|
||||||
|
// Adjust responsive breakpoint based on effective width after scaling
|
||||||
|
const effectiveWidth = window.innerWidth / navScale;
|
||||||
|
if (effectiveWidth >= 1200) {
|
||||||
|
navbar.classList.add('navbar-expand-lg');
|
||||||
|
navbar.classList.remove('navbar-expand-xl');
|
||||||
|
} else {
|
||||||
|
navbar.classList.add('navbar-expand-xl');
|
||||||
|
navbar.classList.remove('navbar-expand-lg');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
console.log('DPR:', currentDPR, 'isHighDPI:', isHighDPI, 'baseScale:', baseScale, 'navScale:', navScale, 'effective width:', effectiveWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
const dropdowns = document.querySelectorAll('.dropdown-menu');
|
||||||
|
dropdowns.forEach(dropdown => {
|
||||||
|
dropdown.style.transform = `scale(${dropdownScale})`;
|
||||||
|
dropdown.style.transformOrigin = 'top center';
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('Applied dropdown scale:', dropdownScale);
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
let lastDPR = window.devicePixelRatio;
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', scaleNav);
|
||||||
|
window.addEventListener('resize', scaleNav);
|
||||||
|
|
||||||
|
setInterval(() => {
|
||||||
|
const currentDPR = window.devicePixelRatio;
|
||||||
|
if (Math.abs(currentDPR - lastDPR) > 0.01) {
|
||||||
|
lastDPR = currentDPR;
|
||||||
|
scaleNav();
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
</script>
|
</script>
|
||||||
<script th:src="@{'/js/thirdParty/pdf-lib.min.js'}"></script>
|
<script th:src="@{'/js/thirdParty/pdf-lib.min.js'}"></script>
|
||||||
<script th:src="@{'/js/fetch-utils.js'}"></script>
|
<script th:src="@{'/js/fetch-utils.js'}"></script>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<footer th:fragment="footer" id="footer" class="text-center">
|
<footer th:fragment="footer" id="footer" class="text-center">
|
||||||
|
|
||||||
<script type="module" th:src="@{'/js/thirdParty/cookieconsent-config.js'}"></script>
|
<script type="module" th:src="@{'/js/thirdParty/cookieconsent-config.js'}"></script>
|
||||||
<div class="footer-center pb-4">
|
<div class="footer-center">
|
||||||
<!-- Links section -->
|
<!-- Links section -->
|
||||||
<div class="d-flex justify-content-center">
|
<div class="d-flex justify-content-center">
|
||||||
<ul class="list-unstyled footer-link-list">
|
<ul class="list-unstyled footer-link-list">
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
border-bottom-style: solid;
|
border-bottom-style: solid;
|
||||||
border-bottom-width: 1px;
|
border-bottom-width: 1px;
|
||||||
border-color: var(--md-nav-color-on-seperator)">
|
border-color: var(--md-nav-color-on-seperator)">
|
||||||
<div class="container ">
|
<div class="container " style="max-width: 100%;">
|
||||||
<a class="navbar-brand" th:href="${@contextPath}" style="display: flex;">
|
<a class="navbar-brand" th:href="${@contextPath}" style="display: flex;">
|
||||||
<img class="main-icon" th:src="@{'/favicon.svg'}" alt="icon">
|
<img class="main-icon" th:src="@{'/favicon.svg'}" alt="icon">
|
||||||
<span class="icon-text" th:text="${@navBarText}"></span>
|
<span class="icon-text" th:text="${@navBarText}"></span>
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="page-container" style="height:98vh; max-height:98vh; overflow-x:hidden;">
|
<div class="page-container" style="max-height:100vh;">
|
||||||
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
||||||
<div style="transform-origin: center top; flex:0 1 auto; display:flex; flex-direction:column; align-items:center; justify-content:flex-start;" id="scale-wrap">
|
<div style="transform-origin: center top; flex:0 1 auto; display:flex; flex-direction:column; align-items:center; justify-content:flex-start;" id="scale-wrap">
|
||||||
<br class="d-md-none">
|
<br class="d-md-none">
|
||||||
@ -99,6 +99,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
</div>
|
</div>
|
||||||
|
<div style="width:100%; overflow-x:visible;">
|
||||||
<div class="features-container" style=" border-top: 1px;
|
<div class="features-container" style=" border-top: 1px;
|
||||||
border-top-style: solid;
|
border-top-style: solid;
|
||||||
border-color: var(--md-nav-color-on-seperator);
|
border-color: var(--md-nav-color-on-seperator);
|
||||||
@ -115,6 +116,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||||
@ -216,33 +218,76 @@
|
|||||||
</script>
|
</script>
|
||||||
<script th:src="@{'/js/pages/home.js'}" th:inline="javascript"></script>
|
<script th:src="@{'/js/pages/home.js'}" th:inline="javascript"></script>
|
||||||
<script>
|
<script>
|
||||||
function applyScale() {
|
function scaleStuff() {
|
||||||
const baseWidth = 1440;
|
const w = 1440;
|
||||||
const baseHeight = 1000;
|
const h = 1000;
|
||||||
const scaleX = window.innerWidth / baseWidth;
|
|
||||||
const scaleY = window.innerHeight / baseHeight;
|
|
||||||
const scale = Math.max(0.9, Math.min(scaleX, scaleY)); // keep aspect ratio, honor minScale
|
|
||||||
const ui = document.getElementById('scale-wrap');
|
|
||||||
const pageContainer = document.querySelector('.page-container');
|
|
||||||
|
|
||||||
// Calculate available space for content
|
const sx = window.innerWidth / w;
|
||||||
const navbar = document.querySelector('.navbar, nav');
|
const sy = window.innerHeight / h;
|
||||||
const navbarHeight = navbar ? navbar.offsetHeight : 0;
|
const s = Math.max(0.9, Math.min(sx, sy));
|
||||||
const availableHeight = pageContainer.offsetHeight - navbarHeight;
|
const el = document.getElementById('scale-wrap');
|
||||||
const originalHeight = ui.scrollHeight;
|
const container = document.querySelector('.page-container');
|
||||||
|
|
||||||
// Dynamic scale based on available space, with a safety margin
|
const nav = document.querySelector('.navbar, nav');
|
||||||
let finalScale = Math.min(scale * 0.75, (availableHeight * 0.98) / originalHeight);
|
const navH = nav ? nav.offsetHeight : 0;
|
||||||
finalScale = Math.max(0.5, finalScale); // Minimum scale
|
const space = container.offsetHeight - navH;
|
||||||
|
const origH = el.scrollHeight;
|
||||||
|
|
||||||
ui.style.transform = `scale(${finalScale})`;
|
// Progressive bonus based on how tall the screen is
|
||||||
ui.style.transformOrigin = 'top center';
|
const aspectRatio = window.innerWidth / window.innerHeight;
|
||||||
ui.style.height = `${originalHeight * finalScale}px`;
|
const tallScreenBonus = Math.max(0, (1.8 - aspectRatio) * 0.15); // More bonus for taller screens
|
||||||
|
|
||||||
|
let finalS = Math.min(s * 0.75, (space * (0.98 + tallScreenBonus)) / origH);
|
||||||
|
finalS = Math.max(0.7, Math.min(1.0, finalS)); // Never scale above 100%
|
||||||
|
|
||||||
|
el.style.transform = `scale(${finalS})`;
|
||||||
|
el.style.transformOrigin = 'top center';
|
||||||
|
el.style.height = `${origH * finalS}px`;
|
||||||
|
|
||||||
|
// Dynamically adjust features container width based on scale
|
||||||
|
const featuresContainer = document.querySelector('.features-container');
|
||||||
|
if (featuresContainer) {
|
||||||
|
const isRTL = document.documentElement.dir === 'rtl' || document.documentElement.getAttribute('dir') === 'rtl';
|
||||||
|
const dynamicWidth = Math.min(120, 100 / finalS);
|
||||||
|
const offset = (dynamicWidth - 100) / 2;
|
||||||
|
|
||||||
|
featuresContainer.style.width = `${dynamicWidth}%`;
|
||||||
|
|
||||||
|
if (isRTL) {
|
||||||
|
featuresContainer.style.right = `-${offset}%`;
|
||||||
|
featuresContainer.style.left = 'auto';
|
||||||
|
} else {
|
||||||
|
featuresContainer.style.left = `-${offset}%`;
|
||||||
|
featuresContainer.style.right = 'auto';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
let prevW = window.innerWidth;
|
||||||
|
let prevH = window.innerHeight;
|
||||||
|
let prevDPR = window.devicePixelRatio;
|
||||||
|
|
||||||
|
function onResize() {
|
||||||
|
const w = window.innerWidth;
|
||||||
|
const h = window.innerHeight;
|
||||||
|
const dpr = window.devicePixelRatio;
|
||||||
|
|
||||||
|
if (w !== prevW || h !== prevH) {
|
||||||
|
if (dpr === prevDPR) {
|
||||||
|
scaleStuff();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
prevW = w;
|
||||||
|
prevH = h;
|
||||||
|
prevDPR = dpr;
|
||||||
}
|
}
|
||||||
|
|
||||||
applyScale();
|
window.addEventListener('load', () => {
|
||||||
|
setTimeout(scaleStuff, 100);
|
||||||
|
});
|
||||||
|
|
||||||
|
window.addEventListener('resize', onResize);
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user