73 lines
2.3 KiB
JavaScript
Raw Normal View History

2025-12-04 20:29:35 +01:00
/**
* @fileoverview Link Preview Component for Rantii
* @author retoor <retoor@molodetz.nl>
* @description Displays link previews with domain info
* @keywords link, preview, url, external, domain
*/
import { BaseComponent } from './base-component.js';
import { getDomain, sanitizeUrl } from '../utils/url.js';
class LinkPreview extends BaseComponent {
static get observedAttributes() {
return ['url', 'title'];
}
init() {
this.render();
}
render() {
const url = this.getAttr('url');
const title = this.getAttr('title');
if (!url) {
this.setHtml('');
return;
}
const safeUrl = sanitizeUrl(url);
if (!safeUrl) {
this.setHtml('');
return;
}
const domain = getDomain(safeUrl);
const displayTitle = title || safeUrl;
this.addClass('link-preview');
this.setHtml(`
<a href="${safeUrl}" class="link-card" target="_blank" rel="noopener noreferrer">
<div class="link-icon">
<svg viewBox="0 0 24 24" width="20" height="20">
<path fill="currentColor" d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z"/>
</svg>
</div>
<div class="link-info">
<span class="link-title">${this.truncate(displayTitle, 60)}</span>
<span class="link-domain">${domain}</span>
</div>
<div class="link-external">
<svg viewBox="0 0 24 24" width="16" height="16">
<path fill="currentColor" d="M19 19H5V5h7V3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z"/>
</svg>
</div>
</a>
`);
}
truncate(text, length) {
if (text.length <= length) return text;
return text.substring(0, length) + '...';
}
onAttributeChanged(name, oldValue, newValue) {
this.render();
}
}
customElements.define('link-preview', LinkPreview);
export { LinkPreview };