henry pushed to branch tor-browser-149.0a1-16.0-2 at The Tor Project / Applications / Tor Browser Commits: e9a76ea0 by Henry Wilkes at 2026-03-30T16:44:16+01:00 fixup! TB 27476: Implement about:torconnect captive portal within Tor Browser TB 44797: Clean up about:torconnect styling. 1. Do not use `error-pages.css`. This made the previous page too quirky and meant we had to deal with styling interference from mozilla. We only need a few of our own CSS additions to cover the useful styling we inherited before. 2. Rather than share elements, each stage will get its own `torconnect-stage-content` element, which will show the corresponding stage. This should simplify the javascript once this is complete. And it should make future adjustments easier. See below. 3. Change the body `display` to `grid`, which can dynamically handle the spacing of all elements. One improvement is that this will ensure that the progress bar's shadow will not overlap the title when the vertical height is narrow. 4. Simplify some of the styling spacing logic. 5. Some other minor clean ups. Example markup that will be used in the future: ```html <div class="torconnect-stage-content" data-stage-name="Start"> <img class="torconnect-icon" alt="" /> <h1 class="torconnect-heading" tabindex="-1"></h1> <div class="torconnect-text-container"> <!-- Text content, etc. --> </div> <div class="torconnect-controls-container"> <!-- Buttons, etc. --> </div> </div> ``` - - - - - 3 changed files: - browser/components/torconnect/content/aboutTorConnect.css - browser/components/torconnect/content/aboutTorConnect.html - browser/components/torconnect/content/aboutTorConnect.js Changes: ===================================== browser/components/torconnect/content/aboutTorConnect.css ===================================== @@ -1,6 +1,5 @@ /* Copyright (c) 2021, The Tor Project, Inc. */ -@import url("chrome://global/skin/error-pages.css"); @import url("chrome://global/skin/onion-pattern.css"); body:not(.loaded) { @@ -8,7 +7,23 @@ body:not(.loaded) { display: none; } +body { + margin: 0; + min-height: 100vh; + --progress-shadow-height: 66px; + display: grid; + grid-template: + "progress progress progress progress progress" minmax(calc(var(--progress-shadow-height) + var(--space-large)), 10vh) + ". . breadcrumbs . ." auto + ". icon heading . ." auto + ". icon text-container . ." auto + ". . controls-container . ." auto + ". . . . ." minmax(var(--onion-pattern-height), 1fr) + / var(--space-large) minmax(max-content, 1fr) minmax(350px, 700px) 1fr var(--space-large); +} + #breadcrumbs { + grid-area: breadcrumbs; display: flex; align-items: center; margin: 0 0 var(--space-xlarge) 0; @@ -78,11 +93,6 @@ body:not(.loaded) { display: none; } -#tor-connect-heading { - /* Do not show the focus outline. */ - outline: none; -} - #connect-to-tor { margin-inline-start: 0; } @@ -95,10 +105,6 @@ body:not(.loaded) { list-style-image: url("chrome://browser/content/torconnect/tor-connect-broken.svg"); } -#location-settings-icon { - list-style-image: url("chrome://browser/content/torconnect/globe.svg"); -} - #try-bridge { cursor: default; } @@ -107,38 +113,17 @@ body:not(.loaded) { list-style-image: url("chrome://browser/content/torconnect/bridge.svg"); } -#locationDropdownLabel { - margin-block: auto; - margin-inline: var(--space-xsmall); -} - #locationDropdownLabel.error { color: var(--text-color-error); } -/* this follows similar css in error-pages.css for buttons */ -@media only screen and (min-width: 480px) { - form#locationDropdown { - margin-inline: var(--space-xsmall); - /* subtracting out the margin is needeed because by - default forms have different margins than buttons */ - max-width: calc(100% - 2 * var(--space-xsmall)); - } -} - -@media only screen and (max-width: 480px) { - #tryAgainButton { - margin-top: var(--space-xsmall); - } -} - form#locationDropdown { width: 240px; } form#locationDropdown select { - max-width: 100%; - margin-inline: 0; + width: 100%; + margin: 0; font-weight: var(--font-weight-bold); } @@ -154,9 +139,7 @@ form#locationDropdown select { } #progressBar:not([hidden]) { - position: fixed; - inset-block-start: 0; - inset-inline: 0; + grid-area: progress; display: grid; --progress-percent: 0%; --progress-animation: progressAnimation 5s ease infinite; @@ -176,7 +159,7 @@ form#locationDropdown select { #progressBackground { z-index: 1; width: var(--progress-percent); - height: 66px; + height: var(--progress-shadow-height); margin-block-start: -26px; background-image: linear-gradient(var(--progressbar-shadow-start), var(--background-color-canvas) 100%), var(--progressbar-gradient); animation: var(--progress-animation); @@ -223,46 +206,94 @@ form#locationDropdown select { } } -#connectPageContainer { - margin-top: 10vh; - width: 100%; - max-width: 45em; -} - #quickstartToggle { width: max-content; } -/* mirrors p element spacing */ #viewLogButton { - margin: var(--space-large) 0; + margin-inline: 0; + margin-block-start: var(--space-large); } -body.aboutTorConnect { - justify-content: space-between; - /* Always reserve 150px for the background, plus padding with content. */ - padding-block-end: calc(var(--onion-pattern-height) + var(--space-large)); +.torconnect-stage-content:not(.show-stage) { + display: none; } -body.aboutTorConnect .title { - background-image: url("chrome://browser/content/torconnect/tor-connect.svg"); +.torconnect-stage-content { + display: contents; +} + +.torconnect-icon { + grid-area: icon; + justify-self: end; + width: 52px; + height: 52px; + margin-inline-end: var(--space-xlarge); + content: url("chrome://browser/content/torconnect/tor-connect.svg"); -moz-context-properties: stroke, fill, fill-opacity; fill-opacity: 1; fill: var(--icon-color); stroke: var(--icon-color); - /* Make sure there is no padding between the title and #breadcrumbs. */ - padding-block-start: 0; + /* Make non-interactive (non-draggable). */ + pointer-events: none; } -body.aboutTorConnect .title.offline { - background-image: url("chrome://browser/content/torconnect/connection-failure.svg"); +.torconnect-icon.offline-icon { + content: url("chrome://browser/content/torconnect/connection-failure.svg"); } -body.aboutTorConnect .title:is(.assist, .final) { - background-image: url("chrome://browser/content/torconnect/tor-connect-broken.svg"); +.torconnect-icon.assist-icon { + content: url("chrome://browser/content/torconnect/tor-connect-broken.svg"); } -body.aboutTorConnect .title.location { - background-image: url("chrome://browser/content/torconnect/connection-location.svg"); +.torconnect-icon.location-icon { + content: url("chrome://browser/content/torconnect/connection-location.svg"); stroke: var(--icon-color-warning); } + +.torconnect-heading { + grid-area: heading; + /* Do not show the focus outline. */ + outline: none; + font-size: var(--font-size-xxxlarge); + margin: 0; + margin-block-end: var(--space-xxlarge); +} + +.torconnect-text-container { + grid-area: text-container; +} + +.torconnect-text-container p { + margin: 0; +} + +.torconnect-text-container > *:not(:last-child) { + margin-block-end: var(--space-large); +} + +.torconnect-controls-container { + grid-area: controls-container; + margin-block: var(--space-xlarge) var(--space-large); + display: flex; + flex-wrap: wrap; + flex-direction: row; + justify-content: end; + align-items: center; + /* Gap between children and rows. */ + gap: var(--space-small) var(--space-small); +} + +.torconnect-controls-container > * { + flex: 0 0 max-content; + margin: 0; +} + +/* Temporary hacks for the connectPageContainer. */ +#connectPageContainer .torconnect-text-container > *:last-child { + margin-block-end: var(--space-large); +} + +#connectPageContainer .torconnect-controls-container { + margin-block-start: calc(var(--space-xlarge) - var(--space-large)); +} ===================================== browser/components/torconnect/content/aboutTorConnect.html ===================================== @@ -8,12 +8,11 @@ /> <title data-l10n-id="tor-connect-page-title"></title> + <link rel="stylesheet" href="chrome://global/skin/in-content/common.css" /> <link rel="stylesheet" href="chrome://global/skin/tor-common.css" /> <link rel="stylesheet" href="chrome://browser/content/torconnect/aboutTorConnect.css" - type="text/css" - media="all" /> <link rel="localization" href="toolkit/global/tor-browser.ftl" /> @@ -23,39 +22,42 @@ src="chrome://global/content/elements/moz-toggle.mjs" ></script> </head> - <body class="aboutTorConnect onion-pattern-background"> + <body class="onion-pattern-background"> <div id="progressBar" hidden="hidden"> <div id="progressSolid"></div> <div id="progressBackground"></div> <div id="progressBarBackground"></div> </div> - <div id="connectPageContainer" class="container"> - <div id="breadcrumbs" class="hidden"> - <span id="connect-to-tor" class="breadcrumb-item"> - <span id="connect-to-tor-icon" class="breadcrumb-icon"></span> - <span class="breadcrumb-label"></span> - </span> - <span - id="connection-assist-separator" - class="breadcrumb-separator breadcrumb-icon" - ></span> - <span id="connection-assist" class="breadcrumb-item"> - <span id="connection-assist-icon" class="breadcrumb-icon"></span> - <span class="breadcrumb-label"></span> - </span> - <span - id="try-bridge-separator" - class="breadcrumb-separator breadcrumb-icon" - ></span> - <span id="try-bridge" class="breadcrumb-item"> - <span id="try-bridge-icon" class="breadcrumb-icon"></span> - <span class="breadcrumb-label"></span> - </span> - </div> - <div id="text-container"> - <div class="title"> - <h1 id="tor-connect-heading" class="title-text" tabindex="-1"></h1> - </div> + <div id="breadcrumbs" class="hidden"> + <span id="connect-to-tor" class="breadcrumb-item"> + <span id="connect-to-tor-icon" class="breadcrumb-icon"></span> + <span class="breadcrumb-label"></span> + </span> + <span + id="connection-assist-separator" + class="breadcrumb-separator breadcrumb-icon" + ></span> + <span id="connection-assist" class="breadcrumb-item"> + <span id="connection-assist-icon" class="breadcrumb-icon"></span> + <span class="breadcrumb-label"></span> + </span> + <span + id="try-bridge-separator" + class="breadcrumb-separator breadcrumb-icon" + ></span> + <span id="try-bridge" class="breadcrumb-item"> + <span id="try-bridge-icon" class="breadcrumb-icon"></span> + <span class="breadcrumb-label"></span> + </span> + </div> + <div id="connectPageContainer" class="torconnect-stage-content"> + <img id="tor-connect-icon" class="torconnect-icon" alt="" /> + <h1 + id="tor-connect-heading" + class="torconnect-heading" + tabindex="-1" + ></h1> + <div class="torconnect-text-container"> <div id="connectLongContent"> <p id="connectLongContentText"></p> </div> @@ -68,26 +70,21 @@ <div id="quickstartContainer"> <moz-toggle id="quickstartToggle"></moz-toggle> </div> - - <div id="connectButtonContainer" class="button-container"> - <button id="restartButton" hidden="true"></button> - <button id="configureButton" hidden="true"></button> - <button id="cancelButton" hidden="true"></button> - <button id="connectButton" hidden="true" class="tor-button"></button> - <label id="locationDropdownLabel" for="countries"></label> - <form id="locationDropdown" hidden="true"> - <select id="regions-select"> - <option id="first-region-option"></option> - <optgroup id="frequent-regions-option-group"></optgroup> - <optgroup id="full-regions-option-group"></optgroup> - </select> - </form> - <button - id="tryBridgeButton" - hidden="true" - class="tor-button" - ></button> - </div> + </div> + <div class="torconnect-controls-container"> + <button id="restartButton" hidden="true"></button> + <button id="configureButton" hidden="true"></button> + <button id="cancelButton" hidden="true"></button> + <button id="connectButton" hidden="true" class="tor-button"></button> + <label id="locationDropdownLabel" for="countries"></label> + <form id="locationDropdown" hidden="true"> + <select id="regions-select"> + <option id="first-region-option"></option> + <optgroup id="frequent-regions-option-group"></optgroup> + <optgroup id="full-regions-option-group"></optgroup> + </select> + </form> + <button id="tryBridgeButton" hidden="true" class="tor-button"></button> </div> </div> <script src="chrome://browser/content/torconnect/aboutTorConnect.js"></script> ===================================== browser/components/torconnect/content/aboutTorConnect.js ===================================== @@ -28,7 +28,7 @@ const BreadcrumbStatus = Object.freeze({ class AboutTorConnect { selectors = Object.freeze({ textContainer: { - title: "div.title", + icon: "#tor-connect-icon", longContentText: "#connectLongContentText", }, progress: { @@ -72,7 +72,7 @@ class AboutTorConnect { }); elements = Object.freeze({ - title: document.querySelector(this.selectors.textContainer.title), + icon: document.querySelector(this.selectors.textContainer.icon), heading: document.getElementById("tor-connect-heading"), longContentText: document.querySelector( this.selectors.textContainer.longContentText @@ -225,9 +225,9 @@ class AboutTorConnect { setTitle(title, className) { this.elements.heading.textContent = title; - this.elements.title.className = "title"; + this.elements.icon.className = "torconnect-icon"; if (className) { - this.elements.title.classList.add(className); + this.elements.icon.classList.add(className); } } @@ -348,10 +348,22 @@ class AboutTorConnect { // selectRegionOption. this.selectedRegion = stage.defaultRegion; + let prevPageEl = document.querySelector( + ".torconnect-stage-content.show-stage" + ); + let pageEl = document.getElementById("connectPageContainer"); + for (const maybePageEl of document.querySelectorAll( + ".torconnect-stage-content" + )) { + if (maybePageEl.dataset.stageName === stage.name) { + pageEl = maybePageEl; + break; + } + } // By default we want to reset the focus to the top of the page when // changing the displayed page since we want a user to read the new page // before activating a control. - let moveFocus = this.elements.heading; + let moveFocus = pageEl.querySelector(".torconnect-heading"); if (stage.name === "Bootstrapping") { this.preBootstrappingStage = prevStage; @@ -461,6 +473,8 @@ class AboutTorConnect { this.hide(this.elements.viewLogButton); } + prevPageEl?.classList.remove("show-stage"); + pageEl.classList.add("show-stage"); document.body.classList.toggle("loaded", isLoaded); moveFocus.focus(); } @@ -557,7 +571,7 @@ class AboutTorConnect { } showOffline() { - this.setTitle(TorStrings.torConnect.noInternet, "offline"); + this.setTitle(TorStrings.torConnect.noInternet, "offline-icon"); this.setLongText(TorStrings.torConnect.noInternetDescription); this.elements.progressDescription.textContent = TorStrings.torConnect.offline; @@ -573,7 +587,7 @@ class AboutTorConnect { } showChooseRegion(error) { - this.setTitle(TorStrings.torConnect.couldNotConnect, "assist"); + this.setTitle(TorStrings.torConnect.couldNotConnect, "assist-icon"); this.showConfigureConnectionLink(TorStrings.torConnect.assistDescription); this.elements.progressDescription.textContent = this.getMaybeLocalizedError(error); @@ -586,7 +600,7 @@ class AboutTorConnect { } showRegionNotFound() { - this.setTitle(TorStrings.torConnect.errorLocation, "location"); + this.setTitle(TorStrings.torConnect.errorLocation, "location-icon"); this.showConfigureConnectionLink( TorStrings.torConnect.errorLocationDescription ); @@ -601,7 +615,7 @@ class AboutTorConnect { } showConfirmRegion(error) { - this.setTitle(TorStrings.torConnect.isLocationCorrect, "location"); + this.setTitle(TorStrings.torConnect.isLocationCorrect, "location-icon"); this.showConfigureConnectionLink( TorStrings.torConnect.isLocationCorrectDescription ); @@ -616,7 +630,7 @@ class AboutTorConnect { } showFinalError(error) { - this.setTitle(TorStrings.torConnect.finalError, "final"); + this.setTitle(TorStrings.torConnect.finalError, "assist-icon"); this.setLongText(TorStrings.torConnect.finalErrorDescription); this.elements.progressDescription.textContent = this.getMaybeLocalizedError(error); View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/e9a76ea0... -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/e9a76ea0... You're receiving this email because of your account on gitlab.torproject.org. Manage all notifications: https://gitlab.torproject.org/-/profile/notifications | Help: https://gitlab.torproject.org/help