This commit is contained in:
oliver
2026-06-06 06:05:17 -03:00
parent 96a893a384
commit 794c3dd22e
18 changed files with 5583 additions and 232 deletions
+920
View File
@@ -0,0 +1,920 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Derez — My Portal</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<!-- ═══════════════════════════════════════════════════════════
AUTH CARD (shown when not logged in)
════════════════════════════════════════════════════════════════ -->
<div class="auth-card" id="auth-card">
<!-- Logo shown on narrow screens (single-col mode) -->
<div class="auth-logo auth-logo-top">
<div class="auth-logo-icon">
<svg
width="28"
height="28"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.8"
stroke-linecap="round"
stroke-linejoin="round"
>
<rect x="3" y="8" width="18" height="13" rx="2" />
<path d="M9 12h.01M15 12h.01" />
<path d="M9 16h6" />
<path d="M12 8V5" />
<circle
cx="12"
cy="4"
r="1.2"
fill="currentColor"
stroke="none"
/>
</svg>
</div>
<h1 class="auth-title">Derez</h1>
<p class="auth-sub">Your AI agents, managed simply.</p>
</div>
<!-- Sign In / Sign Up toggle (used on narrow screens) -->
<div class="auth-switch">
<button
class="auth-switch-btn active"
data-tab="signin"
onclick="switchAuthTab('signin')"
>
Sign In
</button>
<button
class="auth-switch-btn"
data-tab="signup"
onclick="switchAuthTab('signup')"
>
Hire Agent
</button>
</div>
<div class="auth-forms-wrap">
<!-- ── Sign In pane ── -->
<div class="auth-pane">
<!-- Logo shown in dual-col mode, above Sign In -->
<div class="auth-logo auth-logo-pane">
<div class="auth-logo-icon">
<svg
width="28"
height="28"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.8"
stroke-linecap="round"
stroke-linejoin="round"
>
<rect
x="3"
y="8"
width="18"
height="13"
rx="2"
/>
<path d="M9 12h.01M15 12h.01" />
<path d="M9 16h6" />
<path d="M12 8V5" />
<circle
cx="12"
cy="4"
r="1.2"
fill="currentColor"
stroke="none"
/>
</svg>
</div>
<div>
<h1 class="auth-title">Derez</h1>
<p class="auth-sub">
Your AI agents, managed simply.
</p>
</div>
</div>
<div class="auth-pane-title">Sign In</div>
<form
id="signin-form"
class="auth-form"
onsubmit="
event.preventDefault();
doSignIn();
"
>
<div class="form-group">
<label for="signin-email">Email address</label>
<input
type="email"
id="signin-email"
placeholder="you@example.com"
autocomplete="email"
required
/>
</div>
<div class="form-group">
<label for="signin-password">Password</label>
<input
type="password"
id="signin-password"
placeholder="Your password"
autocomplete="current-password"
required
/>
</div>
<div id="signin-error" class="auth-error"></div>
<button
type="submit"
id="signin-btn"
class="btn btn-primary btn-block"
>
Sign In
</button>
</form>
</div>
<!-- /auth-pane signin -->
<div class="auth-forms-divider"></div>
<!-- ── Sign Up pane ── -->
<div class="auth-pane">
<div class="auth-pane-title">Hire Agent</div>
<div class="pricing-badge">
<div class="pricing-amount">
4,99 <span>USD / month</span>
</div>
<div class="pricing-term">Monthly termination</div>
</div>
<div id="coupon-box" class="coupon-box">
<div class="coupon-input-wrap">
<input
type="text"
id="coupon-input"
class="coupon-input"
placeholder="Coupon code"
onkeydown="handleCouponKey(event)"
autocomplete="off"
spellcheck="false"
/>
<span
id="coupon-spinner"
class="coupon-spinner"
style="display: none"
><div class="spinner spinner-sm"></div
></span>
</div>
<div
id="coupon-error"
class="coupon-error"
style="display: none"
>
Invalid coupon code.
</div>
</div>
<div
id="coupon-success"
class="coupon-success"
style="display: none"
>
<svg
width="13"
height="13"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="3"
stroke-linecap="round"
stroke-linejoin="round"
>
<polyline points="20 6 9 17 4 12" />
</svg>
5 USD OpenRouter credits added &mdash; Order now below
</div>
<form
id="signup-form"
class="auth-form"
style="display: none"
onsubmit="
event.preventDefault();
doSignUp();
"
>
<div class="form-row">
<div class="form-group">
<label for="signup-email">Email address</label>
<input
type="email"
id="signup-email"
placeholder="you@example.com"
autocomplete="email"
required
/>
</div>
<div class="form-group">
<label for="signup-password">Password</label>
<input
type="password"
id="signup-password"
placeholder="Min. 8 characters"
autocomplete="new-password"
required
/>
</div>
</div>
<div class="form-row">
<div class="form-group">
<label for="signup-agent">Agent</label>
<select id="signup-agent">
<option value="hermes">Hermes</option>
<option value="openclaw">OpenClaw</option>
</select>
</div>
<div class="form-group">
<label for="signup-location"
>Loft Location</label
>
<select id="signup-location">
<option value="france">
&#127467;&#127479; France
</option>
</select>
</div>
</div>
<div id="signup-error" class="auth-error"></div>
<div id="signup-success" class="auth-success"></div>
<button
type="submit"
id="signup-btn"
class="btn btn-primary btn-block"
>
Hire Agent
</button>
</form>
</div>
<!-- /auth-pane signup -->
</div>
<!-- /auth-forms-wrap -->
</div>
<!-- /auth-card -->
<!-- ═══════════════════════════════════════════════════════════
APP SHELL (shown when logged in)
════════════════════════════════════════════════════════════════ -->
<div class="app-shell" id="app-shell">
<!-- ── Header ───────────────────────────────────────────── -->
<header class="app-header">
<div class="app-brand">
<svg
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<rect x="3" y="8" width="18" height="13" rx="2" />
<path d="M9 12h.01M15 12h.01" />
<path d="M9 16h6" />
<path d="M12 8V5" />
<circle
cx="12"
cy="4"
r="1.2"
fill="currentColor"
stroke="none"
/>
</svg>
Derez
</div>
<!-- ── Header comment (centre) ───────────────────── -->
<div class="header-comment" id="header-comment-wrap">
<span
id="header-comment-display"
class="comment-empty"
title="Click to edit"
onclick="editComment()"
>Name your Agent</span
>
<div id="header-comment-edit" style="display: none">
<input
id="header-comment-input"
type="text"
maxlength="140"
placeholder="Add a comment…"
onkeydown="handleCommentKey(event)"
/>
<button
id="comment-save-btn"
class="btn btn-ghost btn-sm"
onclick="saveComment()"
>
Save
</button>
<button
class="btn btn-ghost btn-sm"
onclick="cancelComment()"
>
</button>
</div>
</div>
<div class="app-user" id="user-panel-wrap">
<span
class="user-pill"
onclick="toggleUserPanel()"
title="Account settings"
>
<span class="pulse-dot"></span>
<span id="user-email-label"></span>
</span>
<!-- ── User account panel ────────────────────── -->
<div
id="user-panel"
class="user-panel"
style="display: none"
onclick="event.stopPropagation()"
>
<div class="user-panel-header">
<svg
width="13"
height="13"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<circle cx="12" cy="8" r="4" />
<path d="M4 20c0-4 3.6-7 8-7s8 3 8 7" />
</svg>
Account
</div>
<div class="user-panel-row">
<span class="user-panel-label">Email</span>
<span
class="user-panel-val"
id="user-panel-email-val"
></span
>
</div>
<div class="user-panel-divider"></div>
<div class="user-panel-pw">
<div class="form-group">
<label>Change Password</label>
<div class="pw-input-wrap">
<input
type="password"
id="acct-pw-input"
placeholder="New password"
autocomplete="new-password"
oninput="
toggleAccountPwSave(this.value)
"
onkeydown="
if (event.key === 'Enter')
saveAccountPassword();
"
/>
<button
type="button"
id="acct-pw-save-btn"
class="pw-save-btn"
onclick="saveAccountPassword()"
title="Save password"
style="display: none"
>
<svg
width="14"
height="14"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2.5"
stroke-linecap="round"
stroke-linejoin="round"
>
<polyline points="20 6 9 17 4 12" />
</svg>
</button>
</div>
</div>
<p class="ssh-hint" style="margin-bottom: 0">
Min. 8 characters.
</p>
</div>
</div>
<button class="btn btn-ghost btn-sm" onclick="doSignOut()">
<svg
width="13"
height="13"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2.5"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" />
<polyline points="16 17 21 12 16 7" />
<line x1="21" y1="12" x2="9" y2="12" />
</svg>
Sign Out
</button>
</div>
</header>
<!-- ── Agent tabs ────────────────────────────────────────── -->
<div class="agent-tabs-bar" id="agent-tabs-bar">
<div class="tabs-loading">
<div class="spinner"></div>
Loading agents&hellip;
</div>
</div>
<!-- ── Body ──────────────────────────────────────────────── -->
<div class="app-body">
<!-- Demo mode overlay -->
<div id="demo-notice" class="demo-notice">
<span>
<svg
width="14"
height="14"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<rect x="3" y="11" width="18" height="11" rx="2" />
<path d="M7 11V7a5 5 0 0 1 10 0v4" />
</svg>
Sign in to manage your agents
</span>
</div>
<!-- No agents state -->
<div id="no-agents" class="empty-center" style="display: none">
<svg
width="52"
height="52"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.4"
stroke-linecap="round"
stroke-linejoin="round"
>
<rect x="3" y="8" width="18" height="13" rx="2" />
<path d="M9 12h.01M15 12h.01" />
<path d="M9 16h6" />
<path d="M12 8V5" />
<circle
cx="12"
cy="4"
r="1.2"
fill="currentColor"
stroke="none"
/>
</svg>
<p>No agents found for your account.</p>
<p
class="text-muted"
style="font-size: 12px; margin-top: 2px"
>
Sign out and use Sign Up to get your first agent.
</p>
</div>
<!-- Agent panel (one per agent, shown for active tab) -->
<div id="agent-panel" style="display: none">
<div class="content-grid">
<!-- ── LEFT column ─────────────────────────── -->
<div class="content-col">
<!-- Server Actions card -->
<div class="card">
<div class="card-header">
<span class="card-title">
<svg
width="14"
height="14"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<polygon
points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"
/>
</svg>
Agent Actions
</span>
<div style="display: flex; gap: 8px">
<button
id="wizard-toggle-btn"
class="btn btn-ghost btn-sm"
onclick="openWizard()"
>
Integrations
</button>
<button
id="restart-btn"
class="btn btn-ghost btn-sm"
onclick="doRestart()"
>
Restart Agent
</button>
<button
id="open-agent-btn"
class="btn btn-primary btn-sm"
onclick="openAgent()"
>
Open Agent
</button>
</div>
</div>
<div id="server-info-body">
<div class="loading-row">
<div class="spinner"></div>
</div>
</div>
</div>
<!-- Instance Password card -->
<div class="card">
<div class="card-header">
<span class="card-title">
<svg
width="14"
height="14"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<rect
x="3"
y="11"
width="18"
height="11"
rx="2"
/>
<path
d="M7 11V7a5 5 0 0 1 10 0v4"
/>
</svg>
Instance Password
</span>
</div>
<div class="pw-wrap">
<div class="form-group">
<label>New Password</label>
<div class="pw-input-wrap">
<input
type="password"
id="pw-new-input"
placeholder="Enter new password"
autocomplete="new-password"
oninput="
togglePwSave(this.value)
"
onkeydown="
if (event.key === 'Enter')
savePassword();
"
/>
<button
type="button"
id="pw-save-btn"
class="pw-save-btn"
onclick="savePassword()"
title="Save password"
style="display: none"
>
<svg
width="14"
height="14"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2.5"
stroke-linecap="round"
stroke-linejoin="round"
>
<polyline
points="20 6 9 17 4 12"
/>
</svg>
</button>
</div>
</div>
</div>
<p class="ssh-hint">
Changing this updates root access on your
server immediately.
</p>
</div>
<!-- API Keys card -->
<div class="card">
<div class="card-header">
<span class="card-title">
<span
id="keys-status-dot"
class="contract-dot"
style="visibility: hidden"
></span>
API Keys
</span>
</div>
<div id="keys-body">
<div class="loading-row">
<div class="spinner"></div>
</div>
</div>
<p class="ssh-hint">
You can add your own API key directly in
your Agent.
</p>
</div>
</div>
<!-- /content-col left -->
<!-- ── RIGHT column ────────────────────────── -->
<div class="content-col">
<!-- Integrations Wizard card (hidden when WIZZARD=false) -->
<div
id="wizard-card"
class="card"
style="display: none"
>
<div class="card-header">
<span class="card-title">
<svg
width="14"
height="14"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<polygon
points="12 2 2 7 12 12 22 7 12 2"
/>
<polyline
points="2 17 12 22 22 17"
/>
<polyline
points="2 12 12 17 22 12"
/>
</svg>
<span id="wizard-card-title"
>Select Skills</span
>
</span>
</div>
<div id="wizard-body"></div>
<div class="wizard-footer">
<button
class="btn btn-ghost btn-sm"
id="wizard-back-btn"
style="display: none"
onclick="wizardBack()"
>
Back
</button>
<button
class="btn btn-primary btn-sm"
id="wizard-next-btn"
onclick="wizardNext()"
>
Next &rarr;
</button>
</div>
</div>
<!-- Backups card -->
<div class="card card-full">
<div class="card-header">
<span class="card-title">
<svg
width="14"
height="14"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path
d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"
/>
<polyline points="17 8 12 3 7 8" />
<line
x1="12"
y1="3"
x2="12"
y2="15"
/>
</svg>
Backups
</span>
<button
id="make-backup-btn"
class="btn btn-ghost btn-sm"
style="
font-size: 18px;
line-height: 1;
padding: 2px 10px;
"
onclick="makeBackup()"
title="Make Backup"
>
+
</button>
</div>
<div id="backups-body">
<div class="loading-row">
<div class="spinner"></div>
</div>
</div>
</div>
<!-- Contract card -->
<div class="card">
<div class="card-header">
<span class="card-title">
<span
id="contract-status-dot"
class="contract-dot"
style="visibility: hidden"
></span>
Contract
</span>
</div>
<div id="contract-body">
<div class="loading-row">
<div class="spinner"></div>
</div>
</div>
</div>
</div>
<!-- /content-col right -->
</div>
<!-- /content-grid -->
</div>
<!-- /agent-panel -->
</div>
<!-- /app-body -->
<!-- ── Talk to Us ──────────────────────────────────── -->
<div class="talk-wrap" id="talk-wrap">
<button
class="talk-toggle"
id="talk-toggle-btn"
onclick="toggleTalk()"
>
<svg
width="14"
height="14"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path
d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"
/>
</svg>
Talk to Us
<svg
id="talk-chevron"
width="13"
height="13"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2.5"
stroke-linecap="round"
stroke-linejoin="round"
style="margin-left: auto; transition: transform 0.25s"
>
<polyline points="18 15 12 9 6 15" />
</svg>
</button>
<div class="talk-panel" id="talk-panel">
<!-- Left: support chat -->
<div class="talk-col talk-chat-col">
<div class="talk-col-title">Support Chat</div>
<div class="chat-msgs" id="chat-msgs"></div>
<div class="chat-input-row">
<input
id="chat-input"
type="text"
placeholder="Type a message…"
onkeydown="handleChatKey(event)"
/>
<button
id="chat-send-btn"
class="btn btn-primary btn-sm"
onclick="sendChat()"
>
Send
</button>
</div>
</div>
<!-- Right: refer a friend -->
<div class="talk-col talk-refer-col">
<div class="talk-col-title">Refer a Friend</div>
<p class="refer-desc">
When your friend signs up mentioning your email
(<strong id="refer-own-email"></strong>), you earn
<strong>$5 USD</strong> credit on your selected
Agent.
</p>
<div class="refer-form">
<div class="refer-input-row">
<input
id="name"
type="text"
placeholder="Your friend's name"
/>
</div>
<div class="refer-input-row">
<input
id="refer-email"
type="email"
placeholder="friend@example.com"
/>
<button
id="refer-send-btn"
class="btn btn-primary btn-sm"
onclick="sendReferral()"
>
Invite
</button>
</div>
</div>
</div>
</div>
</div>
<!-- /talk-wrap -->
</div>
<!-- /app-shell -->
<!-- ═══════════════════════════════════════════════════════════
CONFIRM DIALOG
════════════════════════════════════════════════════════════════ -->
<div id="confirm-backdrop" class="modal-backdrop">
<div class="modal">
<div class="modal-header">
<span class="modal-title" id="confirm-title">Confirm</span>
</div>
<div class="modal-body">
<p id="confirm-message"></p>
</div>
<div class="modal-footer">
<button class="btn btn-ghost" onclick="confirmClose(false)">
Cancel
</button>
<button
id="confirm-ok-btn"
class="btn btn-danger"
onclick="confirmClose(true)"
>
Confirm
</button>
</div>
</div>
</div>
<!-- ═══════════════════════════════════════════════════════════
TOAST CONTAINER
════════════════════════════════════════════════════════════════ -->
<div id="toast-container"></div>
<script src="app.js"></script>
</body>
</html>