Files
at-container-registry/pkg/hold/admin/src/js/main.js
T

141 lines
4.7 KiB
JavaScript

// HTMX
import htmx from 'htmx.org';
window.htmx = htmx;
// ========================================
// Theme management (system / light / dark)
// ========================================
function getThemePreference() {
return localStorage.getItem('hold-admin-theme') || 'system';
}
function getEffectiveTheme(pref) {
if (pref === 'dark' || pref === 'light') return pref;
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
}
function applyTheme() {
const pref = getThemePreference();
const effective = getEffectiveTheme(pref);
const dark = effective === 'dark';
document.documentElement.classList.toggle('dark', dark);
document.documentElement.setAttribute('data-theme', dark ? 'dark' : 'light');
updateThemeUI(pref);
}
function setTheme(theme) {
localStorage.setItem('hold-admin-theme', theme);
applyTheme();
closeThemeDropdown();
}
function updateThemeUI(pref) {
const iconMap = { system: 'sun-moon', light: 'sun', dark: 'moon' };
document.querySelectorAll('[data-theme-icon] use').forEach(use => {
use.setAttribute('href', `/admin/public/icons.svg#${iconMap[pref] || 'sun-moon'}`);
});
document.querySelectorAll('.theme-option').forEach(option => {
const isSelected = option.dataset.value === pref;
const check = option.querySelector('.theme-check');
if (check) {
check.style.visibility = isSelected ? 'visible' : 'hidden';
}
});
}
function closeThemeDropdown() {
document.querySelectorAll('[data-theme-toggle]').forEach(btn => {
const details = btn.closest('details');
if (details) details.removeAttribute('open');
});
}
// Listen for system theme changes
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
if (getThemePreference() === 'system') {
applyTheme();
}
});
// ========================================
// DID-to-handle lookup
// ========================================
function initDIDLookup() {
const didInput = document.getElementById('did');
const lookupBtn = document.getElementById('lookup-btn');
const handleResult = document.getElementById('handle-result');
if (!didInput || !lookupBtn || !handleResult) return;
async function lookupHandle() {
const did = didInput.value.trim();
if (!did.startsWith('did:')) {
handleResult.innerHTML = '<span class="text-error">Invalid DID format</span>';
return;
}
handleResult.innerHTML = '<span class="text-base-content/50 italic">Looking up...</span>';
try {
let url;
if (did.startsWith('did:plc:')) {
url = `https://plc.directory/${did}`;
} else if (did.startsWith('did:web:')) {
const host = did.replace('did:web:', '').replace(/%3A/g, ':');
url = `https://${host}/.well-known/did.json`;
} else {
handleResult.innerHTML = '<span class="text-error">Unsupported DID method</span>';
return;
}
const resp = await fetch(url);
if (!resp.ok) throw new Error('DID not found');
const doc = await resp.json();
const aka = doc.alsoKnownAs || [];
const handleUri = aka.find(u => u.startsWith('at://'));
if (handleUri) {
const handle = handleUri.replace('at://', '');
handleResult.innerHTML = `<span class="text-success flex items-center gap-1"><svg class="icon size-4" aria-hidden="true"><use href="/admin/public/icons.svg#check-circle"></use></svg> <strong>${handle}</strong></span>`;
} else {
handleResult.innerHTML = '<span class="text-warning">No handle found</span>';
}
} catch (err) {
handleResult.innerHTML = `<span class="text-error">Lookup failed: ${err.message}</span>`;
}
}
lookupBtn.addEventListener('click', lookupHandle);
didInput.addEventListener('blur', function() {
if (this.value.startsWith('did:') && this.value.length > 10) {
lookupHandle();
}
});
}
// ========================================
// Init
// ========================================
document.addEventListener('DOMContentLoaded', () => {
applyTheme();
// Theme dropdown setup
document.querySelectorAll('[data-theme-menu]').forEach(themeMenu => {
themeMenu.querySelectorAll('.theme-option').forEach(option => {
option.addEventListener('click', () => {
setTheme(option.dataset.value);
});
});
});
// DID lookup on crew add page
initDIDLookup();
});
// Export for template onclick handlers
window.setTheme = setTheme;