Allow QA view to be larger than viewport height if necessary (#1790)
Closes #1789 ### Changes - Converts stylesheet in js to css now that it doesn't use any runtime values - Removes fixed height on QA container, and instead sets a min height - Applies `contain: size` to page list & tab content so they don't cause the QA container to stretch - Also updates instances of `h-{n} w-{n}` to `size-{n}` - Removes leftover outlines on text and resource comparison areas from early QA prototyping
This commit is contained in:
		
							parent
							
								
									ed189efef4
								
							
						
					
					
						commit
						d6f2fee279
					
				
							
								
								
									
										27
									
								
								frontend/plugins/contain.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								frontend/plugins/contain.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,27 @@ | ||||
| const plugin = require("tailwindcss/plugin"); | ||||
| module.exports = plugin( | ||||
|   ({ matchUtilities, theme }) => { | ||||
|     matchUtilities( | ||||
|       { | ||||
|         contain: (value) => ({ | ||||
|           contain: value, | ||||
|         }), | ||||
|       }, | ||||
|       { values: theme("contain") }, | ||||
|     ); | ||||
|   }, | ||||
|   { | ||||
|     theme: { | ||||
|       contain: { | ||||
|         none: "none", | ||||
|         strict: "strict", | ||||
|         content: "content", | ||||
|         size: "size", | ||||
|         "inline-size": "inline-size", | ||||
|         layout: "layout", | ||||
|         style: "style", | ||||
|         paint: "paint", | ||||
|       }, | ||||
|     }, | ||||
|   }, | ||||
| ); | ||||
							
								
								
									
										14
									
								
								frontend/plugins/content-visibility.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								frontend/plugins/content-visibility.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,14 @@ | ||||
| const plugin = require("tailwindcss/plugin"); | ||||
| module.exports = plugin(function ({ addUtilities }) { | ||||
|   addUtilities({ | ||||
|     ".content-auto": { | ||||
|       "content-visibility": "auto", | ||||
|     }, | ||||
|     ".content-hidden": { | ||||
|       "content-visibility": "hidden", | ||||
|     }, | ||||
|     ".content-visible": { | ||||
|       "content-visibility": "visible", | ||||
|     }, | ||||
|   }); | ||||
| }); | ||||
| @ -18,7 +18,7 @@ export class BetaIcon extends TailwindElement { | ||||
|       <sl-icon | ||||
|         name="stars" | ||||
|         label="Beta" | ||||
|         class="h-4 w-4 text-theme-green" | ||||
|         class="size-4 text-theme-green" | ||||
|       ></sl-icon> | ||||
|     </sl-tooltip>`; | ||||
|   } | ||||
| @ -44,7 +44,7 @@ export class BetaBadge extends TailwindElement { | ||||
|         <sl-icon | ||||
|           name="stars" | ||||
|           label="Beta feature" | ||||
|           class="h-4 w-4 align-middle" | ||||
|           class="size-4 align-middle" | ||||
|         ></sl-icon | ||||
|         > ${msg("Beta")} | ||||
|       </span> | ||||
|  | ||||
| @ -161,7 +161,7 @@ export class FileUploader extends TailwindElement { | ||||
|             </main> | ||||
|           </section> | ||||
|         </div> | ||||
|         <input class="invisible h-0 w-0" type="submit" /> | ||||
|         <input class="invisible size-0" type="submit" /> | ||||
|       </form> | ||||
|       <div slot="footer" class="flex justify-between"> | ||||
|         <sl-button | ||||
|  | ||||
| @ -78,7 +78,7 @@ export class NewBrowserProfileDialog extends LiteElement { | ||||
|               (this.crawlerChannel = e.detail.value!)} | ||||
|           ></btrix-select-crawler> | ||||
|         </div> | ||||
|         <input class="invisible h-0 w-0" type="submit" /> | ||||
|         <input class="invisible size-0" type="submit" /> | ||||
|       </form> | ||||
|       <div slot="footer" class="flex justify-between"> | ||||
|         <sl-button | ||||
|  | ||||
| @ -95,7 +95,7 @@ export class CollectionMetadataDialog extends LiteElement { | ||||
|           `,
 | ||||
|         )} | ||||
| 
 | ||||
|         <input class="invisible h-0 w-0" type="submit" /> | ||||
|         <input class="invisible size-0" type="submit" /> | ||||
|       </form> | ||||
|       <div slot="footer" class="flex items-center justify-end gap-3"> | ||||
|         <sl-button | ||||
|  | ||||
| @ -9,7 +9,7 @@ import { cached } from "@/utils/weakCache"; | ||||
| 
 | ||||
| export const iconFor = cached( | ||||
|   (severity: Severity | ReviewStatus, classList?: string) => { | ||||
|     const baseClasses = tw`h-4 w-4`; | ||||
|     const baseClasses = tw`size-4`; | ||||
|     switch (severity) { | ||||
|       // Severity
 | ||||
|       case "severe": | ||||
|  | ||||
| @ -96,7 +96,7 @@ export const pageDetails = (page: ArchivedItemQAPage) => | ||||
|           <div class="mb-3 flex text-xs leading-4"> | ||||
|             <sl-icon | ||||
|               name="chat-square-text-fill" | ||||
|               class="mr-2 h-4 w-4 flex-none text-blue-600" | ||||
|               class="mr-2 size-4 flex-none text-blue-600" | ||||
|             ></sl-icon> | ||||
|             ${page.notes[page.notes.length - 1].text} | ||||
|           </div>` | ||||
|  | ||||
| @ -114,7 +114,7 @@ export class QaPageGroup extends TailwindElement { | ||||
|         <div | ||||
|           class="${this.expanded | ||||
|             ? "h-auto" | ||||
|             : "h-0"} overflow-hidden [contain:content] [content-visibility:auto]" | ||||
|             : "h-0"} overflow-hidden contain-content content-auto" | ||||
|           ${ref(this.contentContainer)} | ||||
|         > | ||||
|           <slot></slot> | ||||
|  | ||||
| @ -186,7 +186,7 @@ export class QaPage extends TailwindElement { | ||||
|         <div | ||||
|           class="contentContainer ${this.selected | ||||
|             ? "h-auto" | ||||
|             : "h-0"} overflow-hidden [contain:content] [content-visibility:auto]" | ||||
|             : "h-0"} overflow-hidden contain-content content-auto" | ||||
|         > | ||||
|           <div | ||||
|             class="z-10 -mt-2 ml-6 mr-2 rounded-b-lg border border-solid border-gray-200 bg-neutral-0 px-4 pb-1 pt-4" | ||||
|  | ||||
| @ -472,7 +472,7 @@ export class ArchivedItemDetail extends TailwindElement { | ||||
|             this.activeTab = section; | ||||
|           }} | ||||
|           ><sl-icon | ||||
|             class="h-4 w-4 shrink-0" | ||||
|             class="size-4 shrink-0" | ||||
|             name=${icon} | ||||
|             aria-hidden="true" | ||||
|             library=${iconLibrary} | ||||
| @ -953,7 +953,7 @@ ${this.crawl?.description} | ||||
|                           html` <sl-tooltip content=${msg("Backed up")}>
 | ||||
|                             <sl-icon | ||||
|                               name="clouds-fill" | ||||
|                               class="mr-2 h-4 w-4 shrink-0 align-text-bottom text-success" | ||||
|                               class="mr-2 size-4 shrink-0 align-text-bottom text-success" | ||||
|                             ></sl-icon> | ||||
|                           </sl-tooltip>`, | ||||
|                       )} | ||||
|  | ||||
| @ -447,7 +447,7 @@ export class ArchivedItemDetailQA extends TailwindElement { | ||||
|   }; | ||||
| 
 | ||||
|   private readonly renderLoadingDetail = () => | ||||
|     html`<div class="min-w-32"><sl-spinner class="h-4 w-4"></sl-spinner></div>`; | ||||
|     html`<div class="min-w-32"><sl-spinner class="size-4"></sl-spinner></div>`; | ||||
| 
 | ||||
|   private renderAnalysis(qaRuns: QARun[]) { | ||||
|     const isRunning = | ||||
| @ -611,7 +611,7 @@ export class ArchivedItemDetailQA extends TailwindElement { | ||||
|               (threshold) => html` | ||||
|                 <div class="flex items-center gap-2"> | ||||
|                   <dt | ||||
|                     class="h-4 w-4 flex-shrink-0 rounded" | ||||
|                     class="size-4 flex-shrink-0 rounded" | ||||
|                     style="background-color: ${threshold.cssColor}" | ||||
|                   > | ||||
|                     <span class="sr-only">${threshold.lowerBoundary}</span> | ||||
|  | ||||
| @ -0,0 +1,52 @@ | ||||
| article > * { | ||||
|   min-height: 0; | ||||
| } | ||||
| 
 | ||||
| .qa-grid { | ||||
|   grid-template: | ||||
|     "header" | ||||
|     "pageToolbar" | ||||
|     "tabGroup" | ||||
|     "pageList"; | ||||
|   grid-template-columns: 100%; | ||||
|   grid-template-rows: repeat(5, max-content); | ||||
| } | ||||
| 
 | ||||
| /* Tailwind 'lg' responsive size */ | ||||
| @media only screen and (min-width: 1024px) { | ||||
|   .qa-grid { | ||||
|     grid-template: | ||||
|       "header header" | ||||
|       "pageToolbar pageList" | ||||
|       "tabGroup pageList"; | ||||
|     grid-template-columns: 1fr 35rem; | ||||
|     grid-template-rows: repeat(2, min-content) 1fr; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| .grid--header { | ||||
|   grid-area: header; | ||||
| } | ||||
| 
 | ||||
| .grid--pageToolbar { | ||||
|   grid-area: pageToolbar; | ||||
| } | ||||
| 
 | ||||
| .grid--tabGroup { | ||||
|   grid-area: tabGroup; | ||||
| } | ||||
| 
 | ||||
| .grid--pageList { | ||||
|   grid-area: pageList; | ||||
| } | ||||
| 
 | ||||
| sl-image-comparer::part(divider) { | ||||
|   --divider-width: 1rem; | ||||
|   border-left: 1px solid var(--sl-panel-border-color); | ||||
|   border-right: 1px solid var(--sl-panel-border-color); | ||||
|   box-shadow: var(--sl-shadow-large); | ||||
| } | ||||
| 
 | ||||
| sl-image-comparer::part(handle) { | ||||
|   background-color: transparent; | ||||
| } | ||||
| @ -2,7 +2,7 @@ import { localized, msg, str } from "@lit/localize"; | ||||
| import type { SlRequestCloseEvent, SlTextarea } from "@shoelace-style/shoelace"; | ||||
| import { serialize } from "@shoelace-style/shoelace/dist/utilities/form.js"; | ||||
| import { merge } from "immutable"; | ||||
| import { html, nothing, type PropertyValues } from "lit"; | ||||
| import { html, nothing, unsafeCSS, type PropertyValues } from "lit"; | ||||
| import { customElement, property, query, state } from "lit/decorators.js"; | ||||
| import { cache } from "lit/directives/cache.js"; | ||||
| import { choose } from "lit/directives/choose.js"; | ||||
| @ -12,7 +12,7 @@ import { when } from "lit/directives/when.js"; | ||||
| import { throttle } from "lodash/fp"; | ||||
| import queryString from "query-string"; | ||||
| 
 | ||||
| import { styles } from "./styles"; | ||||
| import stylesheet from "./archived-item-qa.stylesheet.css"; | ||||
| import type * as QATypes from "./types"; | ||||
| import { renderResources } from "./ui/resources"; | ||||
| import { renderScreenshots } from "./ui/screenshots"; | ||||
| @ -48,6 +48,8 @@ import { tw } from "@/utils/tailwind"; | ||||
| 
 | ||||
| const DEFAULT_PAGE_SIZE = 100; | ||||
| 
 | ||||
| const styles = unsafeCSS(stylesheet); | ||||
| 
 | ||||
| type PageResource = { | ||||
|   status?: number; | ||||
|   mime?: string; | ||||
| @ -394,7 +396,7 @@ export class ArchivedItemQA extends TailwindElement { | ||||
|         </h1> | ||||
|       </div> | ||||
| 
 | ||||
|       <article class="qa-grid grid gap-x-6 gap-y-0 snap-start"> | ||||
|       <article class="qa-grid min-h-screen grid gap-x-6 gap-y-0 lg:snap-start"> | ||||
|         <header | ||||
|           class="grid--header flex flex-wrap items-center justify-between gap-1 border-b py-2" | ||||
|         > | ||||
| @ -563,7 +565,7 @@ export class ArchivedItemQA extends TailwindElement { | ||||
|             ${msg("Pages")} | ||||
|           </h3> | ||||
|           <btrix-qa-page-list | ||||
|             class="flex flex-col" | ||||
|             class="flex flex-col lg:contain-size" | ||||
|             .qaRunId=${this.qaRunId} | ||||
|             .itemPageId=${this.itemPageId} | ||||
|             .pages=${this.pages} | ||||
| @ -935,7 +937,7 @@ export class ArchivedItemQA extends TailwindElement { | ||||
|     return html` | ||||
|       <section | ||||
|         aria-labelledby="${this.tab}-tab" | ||||
|         class="flex-1 overflow-hidden lg:pb-3" | ||||
|         class="flex-1 overflow-hidden lg:pb-3 lg:contain-size" | ||||
|       > | ||||
|         ${cache(choosePanel())} | ||||
|       </section> | ||||
|  | ||||
| @ -1,59 +0,0 @@ | ||||
| import { css } from "lit"; | ||||
| 
 | ||||
| export const styles = css` | ||||
|   article > * { | ||||
|     min-height: 0; | ||||
|   } | ||||
| 
 | ||||
|   .qa-grid { | ||||
|     grid-template: | ||||
|       "header" | ||||
|       "pageToolbar" | ||||
|       "tabGroup" | ||||
|       "pageList"; | ||||
|     grid-template-columns: 100%; | ||||
|     grid-template-rows: repeat(5, max-content); | ||||
|   } | ||||
| 
 | ||||
|   /* Tailwind 'lg' responsive size */ | ||||
|   @media only screen and (min-width: 1024px) { | ||||
|     .qa-grid { | ||||
|       /* TODO calculate screen space instead of hardcoding */ | ||||
|       height: 100vh; | ||||
|       /* overflow: hidden; */ | ||||
|       grid-template: | ||||
|         "header header" | ||||
|         "pageToolbar pageList" | ||||
|         "tabGroup pageList"; | ||||
|       grid-template-columns: 1fr 35rem; | ||||
|       grid-template-rows: repeat(2, min-content) 1fr; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   .grid--header { | ||||
|     grid-area: header; | ||||
|   } | ||||
| 
 | ||||
|   .grid--pageToolbar { | ||||
|     grid-area: pageToolbar; | ||||
|   } | ||||
| 
 | ||||
|   .grid--tabGroup { | ||||
|     grid-area: tabGroup; | ||||
|   } | ||||
| 
 | ||||
|   .grid--pageList { | ||||
|     grid-area: pageList; | ||||
|   } | ||||
| 
 | ||||
|   sl-image-comparer::part(divider) { | ||||
|     --divider-width: 1rem; | ||||
|     border-left: 1px solid var(--sl-panel-border-color); | ||||
|     border-right: 1px solid var(--sl-panel-border-color); | ||||
|     box-shadow: var(--sl-shadow-large); | ||||
|   } | ||||
| 
 | ||||
|   sl-image-comparer::part(handle) { | ||||
|     background-color: transparent; | ||||
|   } | ||||
| `;
 | ||||
| @ -100,7 +100,7 @@ export function renderResources(crawlData: ReplayData, qaData: ReplayData) { | ||||
|   // </div>`;
 | ||||
| 
 | ||||
|   return html` | ||||
|     <div class="flex h-full flex-col outline"> | ||||
|     <div class="flex h-full flex-col"> | ||||
|       <div class="flex-1 overflow-auto overscroll-contain"> | ||||
|         ${crawlData?.resources && qaData?.resources | ||||
|           ? renderDiff(crawlData.resources, qaData.resources) | ||||
|  | ||||
| @ -72,7 +72,7 @@ export function renderText(crawlData: ReplayData, qaData: ReplayData) { | ||||
|   </div>`;
 | ||||
| 
 | ||||
|   return html` | ||||
|     <div class=${tw`flex h-full flex-col outline`}> | ||||
|     <div class=${tw`flex h-full flex-col`}> | ||||
|       <div class=${tw`mb-2 flex font-semibold`}> | ||||
|         <h3 id="crawlTextHeading" class=${tw`flex-1`}> | ||||
|           ${msg("Text extracted during crawl")} | ||||
|  | ||||
| @ -1,5 +1,8 @@ | ||||
| const { tailwindTransform } = require("postcss-lit"); | ||||
| 
 | ||||
| const containPlugin = require("./plugins/contain"); | ||||
| const contentVisibilityPlugin = require("./plugins/content-visibility"); | ||||
| 
 | ||||
| const PRIMARY_COLOR = "#0891B2"; | ||||
| 
 | ||||
| const primary = { | ||||
| @ -158,5 +161,9 @@ module.exports = { | ||||
|     include: ["./src/**/*.{ts,js}"], | ||||
|   }, | ||||
| 
 | ||||
|   plugins: [require("@tailwindcss/container-queries")], | ||||
|   plugins: [ | ||||
|     require("@tailwindcss/container-queries"), | ||||
|     containPlugin, | ||||
|     contentVisibilityPlugin, | ||||
|   ], | ||||
| }; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user