Files
deploy-test/animex/login.html
2026-03-29 20:52:57 -05:00

457 lines
14 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, user-scalable=no, viewport-fit=cover"
/>
<title>Select Profile - Animex</title>
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
rel="stylesheet"
/>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"
/>
<link rel="manifest" href="Resources/manifest.json/" />
<meta name="theme-color" content="#0b0b0b" />
<link rel="icon" href="/Resources/Images/icon-196.png" type="image/png" />
<!-- iOS support -->
<link rel="apple-touch-icon" href="/Resources/Images/icon-196.png" />
<style>
:root {
--background-primary: #121212;
--foreground-primary: #e6e6e6;
--foreground-secondary: #a0a0a0;
--background-modal: #252525;
--input-border-color: #3a3a3c;
--accent-primary: #ff9500;
--accent-primary-rgb: 255, 149, 0;
--destructive: #ff453a;
--radius-sm: 8px;
--radius-md: 16px;
}
body {
background-color: var(--background-primary);
color: var(--foreground-primary);
font-family: "Inter", sans-serif;
margin: 0;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
-webkit-font-smoothing: antialiased;
}
.profile-container {
text-align: center;
animation: fadeIn 0.5s ease-in-out;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.profile-container h1 {
font-size: 3rem;
font-weight: 700;
margin-bottom: 2rem;
}
.profile-grid {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 2rem;
margin-bottom: 3rem;
}
.profile-item {
cursor: pointer;
text-align: center;
transition: transform 0.2s ease;
position: relative;
}
.profile-item:not(.add) img {
width: 150px;
height: 150px;
border-radius: var(--radius-md);
object-fit: cover;
margin-bottom: 1rem;
border: 4px solid transparent;
transition: all 0.2s ease;
}
.profile-item:not(.add):hover img {
transform: scale(1.05);
border-color: var(--accent-primary);
}
.profile-item .profile-name {
font-weight: 500;
font-size: 1.2rem;
color: var(--foreground-secondary);
transition: color 0.2s ease;
}
.profile-item:hover .profile-name {
color: var(--foreground-primary);
}
.profile-item.add .add-icon {
width: 150px;
height: 150px;
border-radius: var(--radius-md);
display: flex;
justify-content: center;
align-items: center;
font-size: 3rem;
color: var(--foreground-secondary);
background-color: #2a2a2a;
transition: all 0.2s ease;
margin-bottom: 1rem;
}
.profile-item.add:hover .add-icon {
background-color: var(--accent-primary);
color: white;
transform: scale(1.05);
}
.manage-icon {
position: absolute;
top: 55px;
left: 55px;
width: 40px;
height: 40px;
background: rgba(0, 0, 0, 0.6);
color: white;
border-radius: 50%;
display: none;
justify-content: center;
align-items: center;
font-size: 1.2rem;
}
.manage-mode .manage-icon {
display: flex;
}
.manage-mode .profile-item:hover img {
filter: brightness(0.7);
}
.manage-button {
background: none;
border: 1px solid var(--foreground-secondary);
color: var(--foreground-secondary);
padding: 0.75rem 2rem;
border-radius: var(--radius-sm);
font-size: 1rem;
cursor: pointer;
transition: all 0.2s ease;
}
.manage-button:hover {
border-color: var(--foreground-primary);
color: var(--foreground-primary);
background-color: #2a2a2a;
}
.modal-backdrop {
position: fixed;
inset: 0;
background-color: rgba(0, 0, 0, 0.7);
backdrop-filter: blur(8px);
display: none;
justify-content: center;
align-items: center;
z-index: 1000;
}
.modal-content {
background-color: var(--background-modal);
padding: 2rem;
border-radius: var(--radius-md);
width: 90%;
max-width: 400px;
}
.modal-content h2 {
margin-top: 0;
text-align: center;
}
.form-group {
margin-bottom: 1rem;
}
.form-group label {
display: block;
margin-bottom: 0.5rem;
}
.form-group input {
width: 100%;
padding: 0.75rem;
background-color: var(--background-primary);
border: 1px solid var(--input-border-color);
border-radius: var(--radius-sm);
color: var(--foreground-primary);
font-size: 1rem;
}
.modal-actions {
display: flex;
gap: 1rem;
margin-top: 2rem;
}
.primary-button {
flex-grow: 1;
padding: 0.75rem;
border: none;
border-radius: var(--radius-sm);
font-size: 1rem;
font-weight: 600;
cursor: pointer;
background-color: var(--accent-primary);
color: white;
}
.secondary-button {
flex-grow: 1;
background-color: #3a3a3c;
}
.delete-button {
background-color: var(--destructive);
}
</style>
</head>
<body>
<div class="profile-container" id="profileContainer">
<h1>Who's Watching?</h1>
<div class="profile-grid" id="profileGrid">
<!-- Profiles will be dynamically inserted here -->
</div>
<button class="manage-button" id="manageProfilesBtn">
Manage Profiles
</button>
</div>
<!-- MODAL for Profile Create/Edit -->
<div id="profileModal" class="modal-backdrop">
<div class="modal-content">
<h2 id="profileModalTitle">Create Profile</h2>
<form id="profileForm">
<div class="form-group">
<label for="profileNameInput">Name</label>
<input
type="text"
id="profileNameInput"
required
maxlength="20"
autocomplete="off"
/>
</div>
<div class="modal-actions">
<button
type="button"
id="deleteProfileBtn"
class="primary-button delete-button"
style="display: none"
>
Delete
</button>
<button
type="button"
id="closeProfileModalBtn"
class="primary-button secondary-button"
>
Cancel
</button>
<button type="submit" id="saveProfileBtn" class="primary-button">
Save
</button>
</div>
</form>
</div>
</div>
<script>
document.addEventListener("DOMContentLoaded", () => {
const profileContainer = document.getElementById("profileContainer");
const profileGrid = document.getElementById("profileGrid");
const manageProfilesBtn = document.getElementById("manageProfilesBtn");
const profileModal = document.getElementById("profileModal");
const profileForm = document.getElementById("profileForm");
const profileModalTitle = document.getElementById("profileModalTitle");
const profileNameInput = document.getElementById("profileNameInput");
const closeProfileModalBtn = document.getElementById(
"closeProfileModalBtn"
);
const saveProfileBtn = document.getElementById("saveProfileBtn");
const deleteProfileBtn = document.getElementById("deleteProfileBtn");
let profiles = [];
let isManageMode = false;
let profileToEdit = null;
async function initialize() {
await fetchAndRenderProfiles();
setupEventListeners();
}
async function fetchAndRenderProfiles() {
try {
const response = await fetch("/profiles");
if (!response.ok) throw new Error("Could not fetch profiles");
profiles = await response.json();
renderProfileGrid();
} catch (error) {
console.error(error);
profileGrid.innerHTML =
"<p>Could not load profiles. Is the server running?</p>";
}
}
function renderProfileGrid() {
profileGrid.innerHTML = "";
profiles.forEach((profile) => {
const item = createProfileElement(profile);
profileGrid.appendChild(item);
});
// Add the "Add Profile" button if not at max capacity
if (profiles.length < 10) {
const addProfileItem = createAddProfileElement();
profileGrid.appendChild(addProfileItem);
}
}
function createProfileElement(profile) {
const item = document.createElement("div");
item.className = "profile-item";
item.innerHTML = `
<img src="${profile.avatar_url}" alt="${profile.name}">
<div class="manage-icon"><i class="fas fa-pencil-alt"></i></div>
<div class="profile-name">${profile.name}</div>
`;
item.addEventListener("click", () => handleProfileClick(profile));
return item;
}
function createAddProfileElement() {
const item = document.createElement("div");
item.className = "profile-item add";
item.innerHTML = `
<div class="add-icon"><i class="fas fa-plus"></i></div>
<div class="profile-name">Add Profile</div>
`;
item.addEventListener("click", () => {
profileToEdit = null; // Ensure it's a create operation
openProfileModal();
});
return item;
}
function handleProfileClick(profile) {
if (isManageMode) {
profileToEdit = profile;
openProfileModal(profile);
} else {
loginWithProfile(profile);
}
}
function loginWithProfile(profile) {
localStorage.setItem("currentProfileId", profile.id);
// Redirect to the main app page or settings page
console.log(`Logged in as ${profile.name}`);
window.location.href = "index.html";
}
function toggleManageMode() {
isManageMode = !isManageMode;
profileContainer.classList.toggle("manage-mode", isManageMode);
manageProfilesBtn.textContent = isManageMode
? "Done"
: "Manage Profiles";
}
function openProfileModal(profile = null) {
profileForm.reset();
if (profile) {
profileModalTitle.textContent = "Edit Profile";
profileNameInput.value = profile.name;
deleteProfileBtn.style.display = "block";
} else {
profileModalTitle.textContent = "Create Profile";
deleteProfileBtn.style.display = "none";
}
profileModal.style.display = "flex";
profileNameInput.focus();
}
function closeProfileModal() {
profileModal.style.display = "none";
}
async function handleFormSubmit(e) {
e.preventDefault();
const name = profileNameInput.value.trim();
if (!name) return;
saveProfileBtn.disabled = true;
try {
if (profileToEdit) {
// Edit existing profile - change PATCH to PUT
const response = await fetch(`/profiles/${profileToEdit.id}`, {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
id: profileToEdit.id,
name: name,
avatar_url: profileToEdit.avatar_url,
settings: profileToEdit.settings,
}),
});
if (!response.ok) throw new Error("Failed to update profile");
} else {
// Create new profile
const response = await fetch("/profiles", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name }),
});
if (!response.ok) throw new Error("Failed to create profile");
}
closeProfileModal();
await fetchAndRenderProfiles();
} catch (error) {
console.error(error);
window.parent.showToast("An error occurred. Please try again.");
} finally {
saveProfileBtn.disabled = false;
}
}
async function handleDeleteProfile() {
if (
!profileToEdit ||
!confirm(`Delete profile "${profileToEdit.name}"?`)
) {
return;
}
try {
const response = await fetch(`/profiles/${profileToEdit.id}`, {
method: "DELETE",
});
if (!response.ok) throw new Error("Failed to delete profile");
closeProfileModal();
await fetchAndRenderProfiles();
} catch (error) {
console.error(error);
window.parent.showToast("Could not delete profile.");
}
}
function setupEventListeners() {
manageProfilesBtn.addEventListener("click", toggleManageMode);
profileForm.addEventListener("submit", handleFormSubmit);
closeProfileModalBtn.addEventListener("click", closeProfileModal);
deleteProfileBtn.addEventListener("click", handleDeleteProfile);
}
initialize();
});
</script>
</body>
</html>