|
|
class ClaudeHeader extends HTMLElement { |
|
|
constructor() { |
|
|
super(); |
|
|
} |
|
|
|
|
|
connectedCallback() { |
|
|
this.attachShadow({ mode: 'open' }); |
|
|
this.render(); |
|
|
this.setupEventListeners(); |
|
|
} |
|
|
|
|
|
render() { |
|
|
this.shadowRoot.innerHTML = ` |
|
|
<style> |
|
|
.header { |
|
|
background: rgba(255, 255, 255, 0.8); |
|
|
backdrop-filter: blur(10px); |
|
|
border-bottom: 1px solid #e2e8f0; |
|
|
padding: 1rem 1.5rem; |
|
|
position: sticky; |
|
|
top: 0; |
|
|
z-index: 40; |
|
|
} |
|
|
|
|
|
.header-content { |
|
|
max-width: 1200px; |
|
|
margin: 0 auto; |
|
|
display: flex; |
|
|
justify-content: space-between; |
|
|
align-items: center; |
|
|
} |
|
|
|
|
|
.app-identity { |
|
|
display: flex; |
|
|
flex-direction: column; |
|
|
gap: 0.25rem; |
|
|
} |
|
|
|
|
|
.app-name { |
|
|
font-size: 1.5rem; |
|
|
font-weight: 700; |
|
|
color: #1e293b; |
|
|
cursor: pointer; |
|
|
transition: color 0.2s; |
|
|
} |
|
|
|
|
|
.app-name:hover { |
|
|
color: var(--primary-blue); |
|
|
} |
|
|
|
|
|
.tagline { |
|
|
font-size: 0.875rem; |
|
|
color: #64748b; |
|
|
} |
|
|
|
|
|
.model-selector { |
|
|
position: relative; |
|
|
} |
|
|
|
|
|
.model-button { |
|
|
display: flex; |
|
|
align-items: center; |
|
|
gap: 0.5rem; |
|
|
padding: 0.5rem 1rem; |
|
|
background: white; |
|
|
border: 1px solid #d1d5db; |
|
|
border-radius: 0.75rem; |
|
|
font-size: 0.875rem; |
|
|
font-weight: 500; |
|
|
color: #374151; |
|
|
cursor: pointer; |
|
|
transition: all 0.2s; |
|
|
} |
|
|
|
|
|
.model-button:hover { |
|
|
border-color: var(--primary-blue); |
|
|
background: #f8fafc; |
|
|
} |
|
|
|
|
|
.model-button:disabled { |
|
|
opacity: 0.6; |
|
|
cursor: not-allowed; |
|
|
} |
|
|
|
|
|
.dropdown { |
|
|
position: absolute; |
|
|
top: 100%; |
|
|
right: 0; |
|
|
margin-top: 0.5rem; |
|
|
background: white; |
|
|
border: 1px solid #e2e8f0; |
|
|
border-radius: 0.75rem; |
|
|
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1); |
|
|
z-index: 50; |
|
|
min-width: 200px; |
|
|
display: none; |
|
|
} |
|
|
|
|
|
.dropdown.show { |
|
|
display: block; |
|
|
} |
|
|
|
|
|
.dropdown-item { |
|
|
padding: 0.75rem 1rem; |
|
|
cursor: pointer; |
|
|
transition: background 0.2s; |
|
|
border-bottom: 1px solid #f1f5f9; |
|
|
} |
|
|
|
|
|
.dropdown-item:last-child { |
|
|
border-bottom: none; |
|
|
} |
|
|
|
|
|
.dropdown-item:hover { |
|
|
background: #f8fafc; |
|
|
} |
|
|
|
|
|
.dropdown-item.selected { |
|
|
background: #eff6ff; |
|
|
color: var(--primary-blue); |
|
|
} |
|
|
|
|
|
@media (max-width: 767px) { |
|
|
.header { |
|
|
padding: 0.75rem 1rem; |
|
|
} |
|
|
|
|
|
.app-name { |
|
|
font-size: 1.25rem; |
|
|
} |
|
|
|
|
|
.tagline { |
|
|
display: none; |
|
|
} |
|
|
} |
|
|
</style> |
|
|
|
|
|
<header class="header"> |
|
|
<div class="header-content"> |
|
|
<div class="app-identity"> |
|
|
<div class="app-name" id="appName"> |
|
|
ClaudeVerse AI |
|
|
</div> |
|
|
<div class="tagline"> |
|
|
Powered by Puter.js |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="model-selector"> |
|
|
<button class="model-button" id="modelButton"> |
|
|
<span id="currentModel">Claude Sonnet 4.5</span> |
|
|
<i data-feather="chevron-down" width="16" height="16"></i> |
|
|
</button> |
|
|
|
|
|
<div class="dropdown" id="modelDropdown"> |
|
|
<div class="dropdown-item" data-model="claude-sonnet-4-5">Claude Sonnet 4.5</div> |
|
|
<div class="dropdown-item" data-model="claude-sonnet-4">Claude Sonnet 4</div> |
|
|
<div class="dropdown-item" data-model="claude-opus-4-1">Claude Opus 4.1</div> |
|
|
<div class="dropdown-item" data-model="claude-opus-4">Claude Opus 4</div> |
|
|
<div class="dropdown-item" data-model="claude-haiku-4-5">Claude Haiku 4.5</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</header> |
|
|
`; |
|
|
|
|
|
|
|
|
setTimeout(() => { |
|
|
if (this.shadowRoot.querySelector('[data-feather]')) { |
|
|
feather.replace(); |
|
|
} |
|
|
}, 100); |
|
|
} |
|
|
|
|
|
setupEventListeners() { |
|
|
const appName = this.shadowRoot.getElementById('appName'); |
|
|
const modelButton = this.shadowRoot.getElementById('modelButton'); |
|
|
const modelDropdown = this.shadowRoot.getElementById('modelDropdown'); |
|
|
const currentModel = this.shadowRoot.getElementById('currentModel'); |
|
|
|
|
|
|
|
|
appName.addEventListener('click', () => { |
|
|
document.dispatchEvent(new CustomEvent('claude-new-chat')); |
|
|
}); |
|
|
|
|
|
|
|
|
modelButton.addEventListener('click', () => { |
|
|
if (window.claudeApp.isProcessing) return; |
|
|
|
|
|
const isShowing = modelDropdown.classList.contains('show'); |
|
|
if (isShowing) { |
|
|
modelDropdown.classList.remove('show'); |
|
|
} else { |
|
|
modelDropdown.classList.add('show'); |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
modelDropdown.addEventListener('click', (event) => { |
|
|
const item = event.target.closest('.dropdown-item'); |
|
|
if (item) { |
|
|
const model = item.dataset.model; |
|
|
document.dispatchEvent(new CustomEvent('claude-change-model', { |
|
|
detail: { model } |
|
|
})); |
|
|
|
|
|
|
|
|
currentModel.textContent = this.getModelLabel(model); |
|
|
|
|
|
|
|
|
modelDropdown.classList.remove('show'); |
|
|
|
|
|
|
|
|
item.classList.add('selected'); |
|
|
setTimeout(() => item.classList.remove('selected'), 500); |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
document.addEventListener('click', (event) => { |
|
|
if (!this.contains(event.target)) { |
|
|
modelDropdown.classList.remove('show'); |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
document.addEventListener('claude-model-changed', (event) => { |
|
|
const { model } = event.detail; |
|
|
currentModel.textContent = this.getModelLabel(model); |
|
|
}); |
|
|
} |
|
|
|
|
|
getModelLabel(model) { |
|
|
const modelLabels = { |
|
|
'claude-sonnet-4-5': 'Claude Sonnet 4.5', |
|
|
'claude-sonnet-4': 'Claude Sonnet 4', |
|
|
'claude-opus-4-1': 'Claude Opus 4.1', |
|
|
'claude-opus-4': 'Claude Opus 4', |
|
|
'claude-haiku-4-5': 'Claude Haiku 4.5' |
|
|
}; |
|
|
|
|
|
return modelLabels[model] || model; |
|
|
} |
|
|
} |
|
|
|
|
|
customElements.define('claude-header', ClaudeHeader); |