import i18next, { t } from "i18next"; import { css, html, nothing, PropertyValues } from "lit"; import { customElement, property, queryAssignedElements, state } from "lit/decorators.js"; import { createRef, ref, Ref } from "lit/directives/ref.js"; import { BaseElement } from "../hierarchy/BaseElement"; import { languagesObject, T } from "../translations/Languages"; import { booleanConverter } from "../utils/converters/booleanConverter"; import { ifDefined } from "lit/directives/if-defined.js"; const isChromium = "chrome" in window; @customElement("thermal-app") export class ThermalAppUiElement extends BaseElement { @state() language: string = i18next.language; @queryAssignedElements({ slot: "bar", flatten: true }) barElements!: Array; @queryAssignedElements({ slot: "pre", flatten: true }) preElements!: Array; @queryAssignedElements({ slot: "content", flatten: true }) contentElements!: Array; @property({ type: String, reflect: true }) fullscreen: string = "off"; @property({ type: String, reflect: true, attribute: true, converter: booleanConverter(false) }) showfullscreen: boolean = false; @property( {type: String, reflect: true, attribute: true} ) dark: boolean = false; @property() author?: string; @property() recorded?: string; @property() license?: string; @property() label?: string; @property({type: Object}) onlabel?: () => void; @property({converter: booleanConverter(false)}) chromiumwarning: boolean = false; protected appRef: Ref = createRef(); protected headerRef: Ref = createRef(); protected contentRef: Ref = createRef(); protected observer!: ResizeObserver; connectedCallback(): void { super.connectedCallback(); window.addEventListener("fullscreenchange", () => { if (!document.fullscreenElement) { this.fullscreen = "off"; } }); i18next.on("languageChanged", () => { this.log( "languageChanged", this.language, i18next.language ); this.language = i18next.language; }); } toggleFullscreen() { if (this.fullscreen === "on") { this.fullscreen = "off"; } else { this.fullscreen = "on"; } } protected update(changedProperties: PropertyValues): void { super.update(changedProperties); if ( this.observer === undefined && this.appRef.value instanceof Element && this.contentRef.value !== undefined ) { this.observer = new ResizeObserver((entries) => { const entry = entries[0]; if (this.fullscreen === "on" && this.contentRef.value) { const offsetHeight = 175; const offsetWidth = 0; const windowHeight = entry.contentRect.height; const windowWidth = entry.contentRect.width; const availableHeight = windowHeight - offsetHeight; const availableWidth = windowWidth - offsetWidth; const contentHeight = this.contentRef.value.offsetHeight; const aspect = 4 / 3; let width: number = 0; let height: number = 0; // If define by width only if (contentHeight < availableHeight) { console.log("priorita šířky"); width = availableWidth; height = width / aspect; } else { console.log("priorita výšky"); height = availableHeight; width = height * aspect; } } else if (this.fullscreen === "off" && this.contentRef.value) { this.contentRef.value.removeAttribute( "style" ); } }); this.observer.observe(this.appRef.value!); } } attributeChangedCallback(name: string, _old: string | null, value: string | null): void { super.attributeChangedCallback(name, _old, value); if (name === "fullscreen") { if (value === "on") { this.appRef.value?.requestFullscreen(); // ... } else if (value === "off") { // ... if (document.fullscreenElement) document.exitFullscreen(); } } } static styles = css` :host { font-family: sans-serif; font-weight: normal; font-size: var( --thermal-fs ); line-height: 1em; } .dark { background-color: var( --thermal-slate ) !important; } .container { padding: calc( var( --thermal-gap ) / 3 ); background-color: var( --thermal-slate-light ); border: 1px solid var( --thermal-slate ); border-radius: var( --thermal-radius ); position: relative; } .bar { padding-bottom: calc( var( --thermal-gap ) * 0.5 ); display: flex; gap: 5px; align-items: center; .bar-content { flex-grow: 1; } .bar-separator { flex-grow: 100; content: ""; } } :host([fullscreen="on"]) .container { border: 0; border-radius: 0; box-sizing: border-box; height: 100vh; overflow-y: auto; overflow-x: hidden; padding-top: 0px; .app-header { padding-top: calc( var( --thermal-gap ) / 3 ); } header, .content { width: 100%; } } .app-fullscreen-button { svg { width: 1em; } } .credits { display: flex; width: 100%; flex-wrap: wrap; font-size: calc( var(--thermal-fs-sm) * 0.8 ); & > div { padding-top: calc( var(--thermal-gap) * .5 ); padding-right: var( --thermal-gap ); } } .credits-field { display: inline; opacity: .5; } .credit-value { display: inline; } .content { width: 100%; box-sizing: border-box; } .has-content { margin-top: calc( var(--thermal-gap) * .5); color: var( --thermal-foreground ); &::before { opacity: .5; font-size: calc( var(--thermal-fs-sm) * 0.8 ); display: block; padding-bottom: calc( var(--thermal-gap) * .5); } } .app-header { position: sticky; top: 0; z-index: 9999; background: var(--thermal-slate-light); background: linear-gradient(var(--thermal-slate-light) calc(100% - 10px), transparent); } footer.chromium { color: var(--thermal-foreground); font-size: 12px; opacity: .5; display: flex; gap: 5px; margin-top: 10px; svg { width: 1em; } a { color: var(--thermal-foreground); } } `; protected render(): unknown { const showChromiumWarning = isChromium === true && this.chromiumwarning === true; return html`
${this.label ? html`${this.label}` : nothing }
${ this.showfullscreen === true ? html` ${this.fullscreen === "on" ? html` ` : html` ` }
` : nothing } ${this.language.toUpperCase()} ${[ "en", "cs", "de", "fr", "cy", ].map( lang => html`
{ i18next.changeLanguage( lang ); this.language = lang; }} >${languagesObject[lang].flag} ${languagesObject[lang].name}
` )}
${this.preElements.length >= 0 ? html`
` : ""}
${this.author || this.license || this.recorded ? html`
${this.recorded ? html`
${t(T.recordedat)}:
${this.recorded}
` : nothing } ${this.author ? html`
${t(T.author)}:
${this.author}
` : nothing } ${this.license ? html`
${t(T.license)}:
${this.license}
` : nothing }
` : nothing }
${showChromiumWarning === true ? html`` : nothing } ` } }