Newer
Older
iuav-ui / src / components / card / nav-card.ts
/**
 * @license
 * Copyright 2019 Google LLC
 * SPDX-License-Identifier: BSD-3-Clause
 */

import {LitElement, html, css } from 'lit';
import {customElement, property, query} from 'lit/decorators.js';
import { breakpoints } from '../../breakpoints';

@customElement('iu-nav-card')

export class NavCard extends LitElement {

    @query('.title p') private titleElement!: HTMLParagraphElement

    static override styles = css`
        :host{
        display: block;
        }
        .nav-card{
            background: var(--iu-color-grey-100);
            display: block;
            aspect-ratio: 1/1;
            display: flex;
            flex-direction: column;
            justify-content: end;
            padding: var(--iu-grid-gutter);
            color: var(--iu-color-black);
            text-decoration: none;
            font-size: var(--iu-fs-lg);
            &:hover{
                background: var(--iu-color-black);
                color: var(--iu-color-white);
            }
            p{
                justify-self: end;
                margin: 0;
            }
        }
        .excerpt{
            font-size: var(--iu-fs-1);
            margin-bottom: var(--iu-spacing-5);
            flex-grow: 1;
        }
        .subtitle{
            font-size: var(--iu-fs-1);
            color: var(--iu-color-grey-300);
            margin-bottom: var(--iu-spacing-5);
            flex-grow: 1;
        }
        .title{
            display: flex;
            align-items: end;
            overflow: hidden;
            flex-shrink: 1;
        }
        svg{
            width: 27px;
            height: 20px;
            flex-shrink: 0;
            margin-bottom: 10px;
            margin-left: 20px;
        }
    `;

    @property() href : string = '';
    @property() text : string = '';
    @property() excerpt? : string;
    @property() subtitle? : string;


    private isExternalLink(url: string): boolean {
        try {
            const link = new URL(url, window.location.href);
            return link.hostname !== window.location.hostname;
        } catch (e) {
            return false;
        }
    }

    private renderIntIcon() {
        return html`<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 27 20">
        <path fill-rule="evenodd" clip-rule="evenodd" d="m22.711 9-6.778-7.32L17.4.32 26.363 10 17.4 19.68l-1.467-1.36L22.71 11H0V9h22.711Z" fill="currentColor"/></svg>`;
    }

    private renderExtIcon() {
        return html`<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 27 20">
        <path fill-rule="evenodd" clip-rule="evenodd" d="m23.06 2.526-9.97-.383.077-1.998 13.182.507.506 13.181-1.998.077-.383-9.97L8.414 20 7 18.586l16.06-16.06Z" fill="currentColor"/></svg>`;
    }

    private applyMultilineEllipsis(maxLines: number) {
        if (!this.titleElement) return;

        const lineHeight = parseFloat(getComputedStyle(this.titleElement).lineHeight);
        const maxHeight = lineHeight * maxLines;

        if (this.titleElement.scrollHeight > maxHeight) {
            let words = this.titleElement.textContent!.split(' ');
            this.titleElement.textContent = '';

            for (let i = 0; i < words.length; i++) {
                this.titleElement.textContent += words[i] + ' ';
                if (this.titleElement.scrollHeight > maxHeight) {
                    this.titleElement.textContent = this.titleElement.textContent.trim() + '...';
                    break;
                }
            }
        }
    }

    override firstUpdated() {
        // this.applyMultilineEllipsis(2); // Limit to 3 lines
        // window.addEventListener('resize', () => this.applyMultilineEllipsis(3)); // Reapply on resize
    }    
  
    override render() {

        const external = this.isExternalLink(this.href);

        return html`
            <a href="${this.href}" class="nav-card">
                ${this.subtitle ? html`<span class="subtitle">${this.subtitle}</span>` : ''}
                ${this.excerpt && !this.subtitle ? html`<span class="excerpt">${this.excerpt}</span>` : ''}
                <div class="title">
                    <p>${this.text}</p>
                    ${external ? this.renderExtIcon() : this.renderIntIcon()}
                </div>
            </a>
        `;
    }

}

declare global {
  interface HTMLElementTagNameMap {
    'iu-nav-card': NavCard;
  }
}