Rename hst-frontend-new to deck-frontend

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
ARCHITECT
2026-01-13 00:00:56 +00:00
parent 4e9377cf09
commit 030b2a5312
44 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,47 @@
import { Component } from '../Component.ts';
import type { Tag, LangType } from '@/types/index.ts';
import { getName, getImg } from '@/utils/index.ts';
export interface CardProps {
tag: Tag;
lang: LangType;
selected: boolean;
selectionMode: boolean;
onClick: (mrf: string) => void;
onSelect: (mrf: string) => void;
}
export class Card extends Component<CardProps> {
protected template(): string {
const { tag, lang, selected, selectionMode } = this.props;
const img = getImg(tag);
const name = getName(tag, lang);
return `
<div class="card ${selected ? 'selected' : ''}" data-mrf="${tag.mrf}">
${selectionMode ? `
<input type="checkbox" class="card-checkbox" ${selected ? 'checked' : ''}>
` : ''}
${img
? `<img class="card-img" src="${img}" alt="${tag.ref}" loading="lazy">`
: `<div class="card-placeholder">${tag.ref?.slice(0, 2) || 'T'}</div>`
}
<div class="card-name">${name}</div>
</div>
`;
}
protected bindEvents(): void {
const { onClick, onSelect, selectionMode } = this.props;
const mrf = this.props.tag.mrf;
this.element.addEventListener('click', (e) => {
if (selectionMode) {
e.preventDefault();
onSelect(mrf);
} else {
onClick(mrf);
}
});
}
}

View File

@@ -0,0 +1,42 @@
export abstract class Component<P extends object = object> {
protected element: HTMLElement;
protected props: P;
constructor(props: P) {
this.props = props;
this.element = this.createElement();
this.bindEvents();
}
protected abstract template(): string;
protected createElement(): HTMLElement {
const wrapper = document.createElement('div');
wrapper.innerHTML = this.template().trim();
return wrapper.firstElementChild as HTMLElement;
}
protected bindEvents(): void {
// Override in subclasses
}
public mount(container: HTMLElement): void {
container.appendChild(this.element);
}
public unmount(): void {
this.element.remove();
}
public update(props: Partial<P>): void {
this.props = { ...this.props, ...props };
const newElement = this.createElement();
this.element.replaceWith(newElement);
this.element = newElement;
this.bindEvents();
}
public getElement(): HTMLElement {
return this.element;
}
}

View File

@@ -0,0 +1,46 @@
import { Component } from '../Component.ts';
export interface ModalProps {
title: string;
content: string;
isOpen: boolean;
onClose: () => void;
}
export class Modal extends Component<ModalProps> {
protected template(): string {
const { title, content, isOpen } = this.props;
return `
<div class="modal ${isOpen ? 'open' : ''}">
<div class="modal-content">
<div class="modal-header">
<h3>${title}</h3>
<button class="modal-close">&times;</button>
</div>
<div class="modal-body">
${content}
</div>
</div>
</div>
`;
}
protected bindEvents(): void {
const closeBtn = this.element.querySelector('.modal-close');
closeBtn?.addEventListener('click', this.props.onClose);
this.element.addEventListener('click', (e) => {
if (e.target === this.element) {
this.props.onClose();
}
});
}
public open(): void {
this.element.classList.add('open');
}
public close(): void {
this.element.classList.remove('open');
}
}

View File

@@ -0,0 +1,25 @@
import { Component } from '../Component.ts';
export interface TagChipProps {
mrf: string;
label: string;
title?: string;
onClick: (mrf: string) => void;
}
export class TagChip extends Component<TagChipProps> {
protected template(): string {
const { mrf, label, title } = this.props;
return `
<span class="tag-chip" data-mrf="${mrf}" title="${title || ''}">
${label}
</span>
`;
}
protected bindEvents(): void {
this.element.addEventListener('click', () => {
this.props.onClick(this.props.mrf);
});
}
}

View File

@@ -0,0 +1,4 @@
export { Component } from './Component.ts';
export { Card, type CardProps } from './Card/Card.ts';
export { TagChip, type TagChipProps } from './TagChip/TagChip.ts';
export { Modal, type ModalProps } from './Modal/Modal.ts';