CoolFace
Apppublic

onfroy2/tabletop-gallery-explorer

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tabletop-object.js278 linesDownload Raw Back to components
1class TabletopObject extends HTMLElement {2    constructor() {3        super();4        this.attachShadow({ mode: 'open' });5    }6 7    connectedCallback() {8        const type = this.getAttribute('type');9        const title = this.getAttribute('title');10        const color = this.getAttribute('color') || 'blue';11        const image = this.getAttribute('image');12        13        this.shadowRoot.innerHTML = `14            <style>15                :host {16                    display: block;17                    position: absolute;18                    cursor: pointer;19                    transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);20                    outline: none;21                }22                23                :host(:hover) {24                    transform: translateY(-8px) rotateZ(2deg);25                    filter: drop-shadow(0 20px 40px rgba(0, 0, 0, 0.3));26                    z-index: 100;27                }28                29                :host(:focus-visible) {30                    outline: 3px solid #3b82f6;31                    outline-offset: 2px;32                }33                34                .object-container {35                    width: 100%;36                    height: 100%;37                    position: relative;38                }39                40                /* Magazine styles */41                .magazine {42                    background: linear-gradient(135deg, ${this.getColorShades(color)[0]} 0%, ${this.getColorShades(color)[1]} 100%);43                    border-radius: 4px;44                    box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);45                    position: relative;46                    overflow: hidden;47                }48                49                .magazine::before {50                    content: '';51                    position: absolute;52                    inset: 0;53                    background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);54                    transform: translateX(-100%);55                }56                57                .magazine:hover::before {58                    animation: shimmer 1.5s infinite;59                }60                61                @keyframes shimmer {62                    100% { transform: translateX(100%); }63                }64                65                .magazine-title {66                    writing-mode: vertical-rl;67                    text-orientation: mixed;68                    color: white;69                    font-weight: bold;70                    font-size: 14px;71                    padding: 12px 8px;72                    text-align: center;73                    height: 100%;74                    display: flex;75                    align-items: center;76                    justify-content: center;77                }78                79                /* Resource/file styles */80                .file-folder {81                    background: linear-gradient(135deg, #fbbf24 0%, #f59e0b 100%);82                    border-radius: 8px;83                    box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);84                    position: relative;85                }86                87                .file-folder::after {88                    content: '';89                    position: absolute;90                    top: 0;91                    right: 12px;92                    width: 30px;93                    height: 10px;94                    background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);95                    border-radius: 0 0 8px 8px;96                }97                98                .file-label {99                    position: absolute;100                    bottom: 8px;101                    left: 8px;102                    right: 8px;103                    background: rgba(0, 0, 0, 0.7);104                    color: white;105                    padding: 4px 8px;106                    border-radius: 4px;107                    font-size: 12px;108                }109                110                /* Art frame styles */111                .art-frame {112                    background: linear-gradient(135deg, #d97706 0%, #92400e 100%);113                    padding: 12px;114                    border-radius: 4px;115                    box-shadow: 116                        inset 0 0 20px rgba(0, 0, 0, 0.3),117                        0 10px 30px rgba(0, 0, 0, 0.2);118                }119                120                .art-canvas {121                    background: #f3f4f6;122                    border-radius: 2px;123                    overflow: hidden;124                    position: relative;125                }126                127                .art-image {128                    width: 100%;129                    height: 100%;130                    object-fit: cover;131                }132                133                .art-title {134                    position: absolute;135                    bottom: 0;136                    left: 0;137                    right: 0;138                    background: linear-gradient(to top, rgba(0, 0, 0, 0.8), transparent);139                    color: white;140                    padding: 12px 8px 8px;141                    font-size: 12px;142                    font-weight: bold;143                }144                145                /* Demo device styles */146                .device {147                    background: #1f2937;148                    border-radius: 20px;149                    padding: 20px;150                    box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);151                    position: relative;152                }153                154                .device-screen {155                    background: #000;156                    border-radius: 10px;157                    overflow: hidden;158                }159                160                .device-image {161                    width: 100%;162                    height: 100%;163                    object-fit: cover;164                }165                166                .device-title {167                    position: absolute;168                    bottom: -32px;169                    left: 50%;170                    transform: translateX(-50%);171                    background: rgba(255, 255, 255, 0.9);172                    backdrop-filter: blur(8px);173                    padding: 6px 16px;174                    border-radius: 20px;175                    font-size: 14px;176                    font-weight: 500;177                    white-space: nowrap;178                }179            </style>180            181            <div class="object-container">182                ${this.renderObject(type, title, color, image)}183            </div>184        `;185        186        this.setupInteractions();187    }188    189    getColorShades(color) {190        const colorMap = {191            blue: ['#3b82f6', '#1d4ed8'],192            purple: ['#8b5cf6', '#6d28d9'],193            green: ['#10b981', '#047857'],194            red: ['#ef4444', '#dc2626'],195            orange: ['#f97316', '#ea580c'],196            pink: ['#ec4899', '#db2777'],197            yellow: ['#f59e0b', '#d97706']198        };199        return colorMap[color] || colorMap.blue;200    }201    202    renderObject(type, title, color, image) {203        switch(type) {204            case 'magazine':205                return `206                    <div class="magazine w-32 h-44">207                        <div class="magazine-title">${title}</div>208                    </div>209                `;210                211            case 'resource':212                return `213                    <div class="file-folder w-24 h-32">214                        <div class="file-label">${title}</div>215                    </div>216                `;217                218            case 'art':219                return `220                    <div class="art-frame">221                        <div class="art-canvas w-48 h-32">222                            <img src="${image}" alt="${title}" class="art-image">223                            <div class="art-title">${title}</div>224                        </div>225                    </div>226                `;227                228            case 'demo':229                return `230                    <div class="device w-64 h-40">231                        <div class="device-screen">232                            <img src="${image}" alt="${title}" class="device-image">233                        </div>234                        <div class="device-title">${title}</div>235                    </div>236                `;237                238            default:239                return '<div>Unknown object type</div>';240        }241    }242    243    setupInteractions() {244        this.addEventListener('click', (e) => {245            this.dispatchEvent(new CustomEvent('object-click', {246                detail: {247                    id: this.getAttribute('object-id'),248                    type: this.getAttribute('type'),249                    title: this.getAttribute('title')250                },251                bubbles: true252            }));253        });254        255        // Adding hover preview256        this.addEventListener('mouseenter', () => {257            this.dispatchEvent(new CustomEvent('object-hover', {258                detail: {259                    id: this.getAttribute('object-id'),260                    type: this.getAttribute('type'),261                    title: this.getAttribute('title')262                },263                bubbles: true264            }));265        });266        267        this.addEventListener('mouseleave', () => {268            this.dispatchEvent(new CustomEvent('object-unhover', {269                detail: {270                    id: this.getAttribute('object-id')271                },272                bubbles: true273            }));274        });275    }276}277 278customElements.define('tabletop-object', TabletopObject);