Files
Frederik Spirgi 8666e09049
CI / check (22) (push) Failing after 16m26s
CI / check (24) (push) Failing after 15m50s
make some overall QoL improvements
2026-10-08 11:02:32 +02:00

460 lines
33 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/img/favicon.svg">
<title>Elsewhere</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link
href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;700&family=Manrope:wght@400;500;600;700;800&display=swap"
rel="stylesheet">
<script src="/js/theme-bootstrap.js?v=20260909-account-controls"></script>
<link rel="stylesheet" href="/css/style.css?v=20261008-conversation-search" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="/css/pages.css?v=20260909-account-controls">
<link rel="stylesheet" href="/css/shell.css?v=20260909-account-controls">
</head>
<body class="site-page chat-page" data-theme="fakegpt" data-theme-mode="light">
<!-- site-header -->
<div class="app-shell">
<section id="chat" class="card chat-card chat-focus-card hidden" aria-label="AI chat workspace">
<div class="chat-layout chat-layout-focus">
<aside id="chatSidebar" class="chat-sidebar" aria-label="Conversation history">
<div class="sidebar-top">
<div class="sidebar-workspace-card">
<h2>Conversations</h2><button id="newChat" class="primary-action" type="button">New
chat</button>
</div>
<label class="field compact-field">
<span>Search</span>
<input id="chatSearch" type="search" placeholder="Search chats" />
</label>
</div>
<div class="sidebar-middle">
<div id="chatList" class="chat-list chat-list-grouped"></div>
<div id="chatListLoading" class="chat-loading hidden" role="status" aria-live="polite">
<span class="chat-loading-dot" aria-hidden="true"></span>
<span id="chatListLoadingText">Loading chats...</span>
</div>
</div>
</aside>
<button id="chatSidebarBackdrop" class="chat-sidebar-backdrop" type="button"
aria-label="Close conversation history" hidden></button>
<section id="main" class="chat-main chat-main-focus" aria-label="Active conversation">
<div class="chat-heading">
<p id="workspaceNotice" class="status error hidden" role="status" aria-live="polite"></p>
<header class="chat-header chat-header-focus">
<button id="chatSidebarToggle" class="icon-button sidebar-toggle" type="button"
aria-controls="chatSidebar" aria-expanded="false"
aria-label="Open conversation history">History</button>
<div class="chat-title-block">
<div class="chat-title">
<h2 id="activeChatTitle">New chat</h2>
</div>
<div class="chat-header-context" aria-label="Current chat setup">
<button id="headerModelButton"
class="chat-context-item chat-context-button secondary-action" type="button"
aria-controls="chatDrawer"
aria-label="Change AI model"><span>Model</span><strong
id="headerModelName">Loading...</strong></button>
<label class="chat-context-item"><span>Chat with</span><select id="personalitySelect" aria-label="Conversation personality"></select></label>
</div>
</div>
<div class="chat-header-actions">
<div class="chat-actions-menu">
<button id="chatDrawerButton" class="secondary-action overflow-trigger"
type="button" aria-expanded="false" aria-controls="chatDrawer">
<span class="overflow-trigger-label">Chat settings</span>
</button>
<div id="chatDrawer" class="chat-drawer hidden" role="dialog" aria-modal="true"
aria-labelledby="chatDrawerTitle">
<div class="chat-drawer-panel">
<div class="chat-drawer-header">
<div>
<p class="eyebrow">Conversation</p>
<h2 id="chatDrawerTitle">Settings</h2>
</div>
<button id="chatDrawerClose" class="icon-button" type="button"
aria-label="Close chat settings">×</button>
</div>
<div class="chat-drawer-body">
<div class="chat-drawer-summary">
<div class="chat-drawer-pills">
<span id="chatCharacterPill"
class="context-pill hidden">Character: none</span>
<span id="chatUserPersonaPill" class="context-pill hidden">User
persona: none</span>
</div>
</div>
<details
class="chat-drawer-section chat-drawer-disclosure chat-drawer-section--model"
open>
<summary class="chat-drawer-row">
<span class="chat-drawer-row-label">
<span class="eyebrow">AI model</span>
<strong>Model</strong>
</span>
<span class="chat-drawer-row-meta">
<strong id="modelBadgeName">Loading...</strong>
<span class="chat-drawer-row-hint">Change</span>
</span>
</summary>
<div id="modelPanel"
class="model-panel chat-drawer-disclosure-panel"
data-static-panel="true">
<div class="model-select">
<div class="model-select-header">
<label for="model">Model</label>
<span id="modelCount" class="model-count">Loading</span>
</div>
<div class="model-select-control">
<select id="model">
<option disabled selected>Loading models...</option>
</select>
<span class="model-select-chevron"
aria-hidden="true"></span>
</div>
</div>
<div id="modelHelp" class="model-help" aria-live="polite">
<div class="model-help-header">
<strong id="modelHelpTitle">Choose a model</strong>
<span id="modelHelpBadge"
class="model-help-badge">Waiting</span>
</div>
<p id="modelHelpSummary" class="model-help-summary">Pick a
model to see what it is best suited for.</p>
</div>
</div>
</details>
<details class="chat-drawer-section generation-advanced">
<summary class="chat-drawer-row"><span class="chat-drawer-row-label"><strong>Generation settings</strong></span><span class="chat-drawer-row-hint">Advanced</span></summary>
<div class="generation-settings-grid chat-drawer-disclosure-panel">
<label class="field"><span>Temperature</span><input
id="chatTemperature" type="number" min="0" max="2"
step="0.1" placeholder="Default" /></label>
<label class="field"><span>Context length</span><input
id="chatContextLength" type="number" min="256"
max="131072" placeholder="Default" /></label>
<label class="field"><span>Response length</span><input
id="chatResponseLength" type="number" min="1"
max="32768" placeholder="Default" /></label>
<label class="field field-wide"><span>System
instruction</span><textarea
id="chatSystemInstruction" rows="4" maxlength="8000"
placeholder="Optional instructions for this chat"></textarea></label>
<button id="saveGenerationSettings" type="button">Save
generation settings</button>
</div>
</details>
<div class="chat-drawer-section">
<p class="dropdown-section-label">Conversation actions</p>
<div class="chat-drawer-action-list">
<button id="renameChat"
class="secondary-action chat-drawer-action" type="button"
data-chat-action="rename">Rename chat</button>
<button id="pinChat" class="secondary-action chat-drawer-action"
type="button" data-chat-action="pin">Pin</button>
<button id="archiveChat"
class="secondary-action chat-drawer-action" type="button"
data-chat-action="archive">Archive</button>
<button id="exportChat"
class="secondary-action chat-drawer-action" type="button"
data-chat-action="export">Export</button>
</div>
</div>
<details class="chat-drawer-section chat-drawer-more">
<summary class="chat-drawer-row chat-drawer-row--compact">
<span class="chat-drawer-row-label">
<strong>Conversation tools</strong>
</span>
<span class="chat-drawer-row-hint">Show</span>
</summary>
<div class="chat-drawer-action-list chat-drawer-disclosure-panel">
<button id="moveChatFolder"
class="secondary-action chat-drawer-action" type="button"
data-chat-action="folder">Move to folder</button>
<button id="manageChatMemory"
class="secondary-action chat-drawer-action" type="button"
data-chat-action="memory">Conversation memory</button>
<button id="exploreBranches" type="button" class="secondary-action chat-drawer-action" data-chat-action="branches">Branches &amp; compare</button>
<button id="managePersonaState"
class="secondary-action chat-drawer-action" type="button"
data-chat-action="personaState">Roleplay state</button>
</div>
</details>
<details class="chat-drawer-section chat-drawer-more">
<summary class="chat-drawer-row chat-drawer-row--compact"><span class="chat-drawer-row-label"><strong>Workspace files</strong></span><span class="chat-drawer-row-hint">Show</span></summary>
<div class="chat-drawer-action-list chat-drawer-disclosure-panel">
<button id="backupWorkspace"
class="secondary-action chat-drawer-action"
type="button">Download workspace archive</button>
<button id="importWorkspace"
class="secondary-action chat-drawer-action"
type="button">Import workspace</button>
<input id="importWorkspaceFile" class="hidden" type="file"
accept="application/json,.json,.tar.gz,application/gzip" />
</div>
</details>
<details class="chat-drawer-section chat-drawer-danger">
<summary class="chat-drawer-row chat-drawer-row--compact">
<span class="chat-drawer-row-label">
<strong>Delete chat content</strong>
</span>
<span class="chat-drawer-row-hint">Show</span>
</summary>
<div class="chat-drawer-action-list chat-drawer-disclosure-panel">
<button id="clearChat"
class="secondary-action chat-drawer-action chat-drawer-action-danger"
type="button" data-chat-action="clear">Clear chat</button>
</div>
</details>
</div>
</div>
</div>
</div>
</div>
</header>
</div>
<div id="chatActivityOverlay" class="chat-activity-overlay hidden" role="status" aria-live="polite"
aria-atomic="true">
<div class="chat-activity-card">
<div class="chat-activity-mark" aria-hidden="true">
<span></span>
<span></span>
<span></span>
</div>
<p id="chatActivityEyebrow" class="eyebrow">Please wait</p>
<h3 id="chatActivityTitle">Preparing chat</h3>
<p id="chatActivityDetail" class="subtitle">The assistant is still working.</p>
</div>
</div>
<div class="messages-wrap">
<div class="history-controls">
<button id="loadOlderMessages" class="secondary-action" type="button" hidden>Load older messages</button>
<button id="loadLatestMessages" class="secondary-action" type="button" hidden>Back to latest messages</button>
</div>
<div class="conversation-search" role="search" aria-label="Search this conversation">
<label for="conversationSearch">Find in this chat</label>
<input id="conversationSearch" type="search" placeholder="Search messages" autocomplete="off" maxlength="200">
<span id="conversationSearchCount" role="status" aria-live="polite">0 matches</span>
<button id="conversationSearchPrevious" class="secondary-action" type="button" aria-label="Previous match" disabled>Previous</button>
<button id="conversationSearchNext" class="secondary-action" type="button" aria-label="Next match" disabled>Next</button>
</div>
<div id="messages" class="messages-panel messages-panel-focus" role="log" aria-live="off"></div>
<div id="replyAnnouncement" class="visually-hidden" role="status" aria-live="polite" aria-atomic="true"></div>
<button id="jumpToLatest" class="jump-to-latest secondary-action hidden" type="button">Jump to latest</button>
</div>
<div class="input-shell input-shell-focus">
<div class="input-meta">
<p id="composerHint" class="composer-hint">Enter to send · Shift+Enter for new line</p>
</div>
<div id="uploadPreviews" class="upload-previews" aria-live="polite" hidden></div>
<div class="input-container">
<input id="imagePicker" type="file" accept="image/png,image/jpeg,image/webp" multiple
hidden>
<button id="attachImage" class="icon-button" type="button" aria-label="Attach image"
title="Attach image">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="1.6" aria-hidden="true">
<rect x="3" y="3" width="18" height="18" rx="3" />
<circle cx="8" cy="8" r="1.5" />
<path d="m3 17 5-5 4 4 4-6 5 7" />
</svg><span class="composer-tool-label">Attach</span>
</button>
<button id="webSearch" class="icon-button" type="button" aria-label="Automatic web search on — click to disable"
title="Automatic web search on — click to disable" aria-pressed="true">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="1.6" aria-hidden="true">
<circle cx="12" cy="12" r="9" />
<ellipse cx="12" cy="12" rx="4" ry="9" />
<path d="M3 12h18" />
</svg><span class="composer-tool-label">Web search</span>
</button>
<button id="reasoning" class="icon-button" type="button" aria-label="Enable reasoning"
title="Enable reasoning" aria-pressed="false" disabled>
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"
aria-hidden="true">
<path
d="M12 18V5a3 3 0 0 0-5.8-1A4 4 0 0 0 3 10a4 4 0 0 0 1 7.8A4 4 0 0 0 12 18ZM12 5a3 3 0 0 1 5.8-1A4 4 0 0 1 21 10a4 4 0 0 1-1 7.8A4 4 0 0 1 12 18M8 8a4 4 0 0 1-5 2m13-2a4 4 0 0 0 5 2M8 14a4 4 0 0 0-4 4m12-4a4 4 0 0 1 4 4" />
</svg><span class="composer-tool-label">Reasoning</span>
</button>
<label class="visually-hidden" for="msgInput">Message</label>
<textarea id="msgInput" rows="1" placeholder="Type your message..."></textarea>
<button id="send" type="button" aria-label="Send message"></button>
<button id="stopGeneration" class="secondary-action" type="button" aria-label="Stop generating reply" hidden>Stop</button>
</div>
</div>
</section>
</div>
</section>
</div>
<div id="personaModal" class="modal-overlay side-panel-overlay hidden">
<div class="modal-card persona-modal-card side-panel-card" role="dialog" aria-modal="true" aria-labelledby="personaFormTitle" tabindex="-1">
<div class="modal-header">
<div class="persona-modal-heading">
<p class="eyebrow">Persona editor</p>
<h3 id="personaFormTitle">Create persona</h3>
</div>
<button id="personaClose" type="button" class="icon-button">Close</button>
</div>
<form id="personaForm" class="persona-form">
<div class="persona-form-intro">
<p class="persona-helper">AI Characters shape who you talk to. User personas add context for who you
are in the scene.</p>
</div>
<p id="personaFormNotice" class="status hidden"></p>
<div class="persona-form-grid">
<label class="field field-wide">
<span>Persona for</span>
<select id="personaType">
<option value="assistant">AI Character</option>
<option value="user">Your persona</option>
</select>
</label>
<label class="field">
<span>Persona name</span>
<input id="personaName" placeholder="Persona name" required />
</label>
<label class="field">
<span>Persona pronouns</span>
<input id="personaPronouns" placeholder="e.g. she/her, they/them" />
</label>
<label class="field field-wide">
<span>Appearance</span>
<textarea id="personaAppearance" rows="3" placeholder="Describe their look"></textarea>
</label>
<label class="field field-wide">
<span>Background</span>
<textarea id="personaBackground" rows="3"
placeholder="Backstory, history, role, or origins"></textarea>
</label>
<label class="field field-wide">
<span>Details</span>
<textarea id="personaDetails" rows="4"
placeholder="Personality traits, voice, goals, quirks, boundaries, style"></textarea>
</label>
<label id="personaExamplesField" class="field field-wide hidden">
<span>Example dialogues</span>
<div class="dialogue-format-card" aria-hidden="true">
<p class="dialogue-format-label">Format</p>
<pre class="dialogue-format-example">{{character}}: Hello, my name is marc
{{user}}: Hi, Marc!
{{character}}: Nice to meet you</pre>
</div>
<textarea id="personaExampleDialogues" rows="5"
placeholder="Write example exchanges that define the AI's tone, phrasing, pacing, and personality."></textarea>
</label>
</div>
<div class="persona-actions">
<button id="personaSave" type="submit" class="primary-action">Save persona</button>
</div>
</form>
</div>
</div>
<div id="roleplayStarterModal" class="modal-overlay side-panel-overlay hidden">
<div class="modal-card roleplay-starter-card side-panel-card" role="dialog" aria-modal="true" aria-labelledby="roleplayStarterTitle" tabindex="-1">
<div class="modal-header">
<div class="persona-modal-heading">
<p class="eyebrow">Start roleplay</p>
<h3 id="roleplayStarterTitle">Choose your roleplay</h3>
</div>
<button id="roleplayStarterClose" type="button" class="icon-button">Close</button>
</div>
<div class="roleplay-starter-intro">
<p id="roleplayStarterIntroCopy" class="persona-helper">Pick a character and choose who you are before
moving on to the opening scene.</p>
</div>
<p id="roleplayStarterNotice" class="status hidden"></p>
<div class="roleplay-starter-actions">
<a id="roleplayNewPersona" class="secondary-action" href="/app/personas">Browse Personalities</a>
</div>
<div id="roleplayStarterStepOne" class="persona-form-grid">
<label class="field field-wide">
<span>1. Character</span>
<select id="roleplayCharacterSelect"></select>
</label>
<label class="field field-wide">
<span>2. You in the scene</span>
<select id="roleplayUserPersonaSelect"></select>
</label>
</div>
<div id="roleplayStarterStepTwo" class="roleplay-starter-page hidden">
<label class="field field-wide">
<span>Optional opening direction</span>
<textarea id="roleplayScenarioInput" rows="4"
placeholder="Describe the kind of opening scene you want, such as a setting, conflict, relationship dynamic, or mood. Leave it empty and the AI will invent its own scenario."></textarea>
</label>
<p class="subtitle">Leave this empty if you want the AI Character to invent the scenario on its own. No
character limit.</p>
<div id="roleplayStarterSuggestions" class="quick-prompts" aria-label="Scenario suggestions"></div>
</div>
<div class="popup-actions">
<button id="roleplayStarterCancel" type="button" class="secondary-action">Cancel</button>
<button id="roleplayStarterBack" type="button" class="secondary-action hidden">Back</button>
<button id="roleplayStarterConfirm" type="button">Continue</button>
</div>
</div>
</div>
<div id="popupModal" class="modal-overlay hidden">
<div class="modal-card popup-card" role="dialog" aria-modal="true" aria-labelledby="popupTitle"
aria-describedby="popupDescription">
<div class="modal-header">
<div class="persona-modal-heading">
<p id="popupEyebrow" class="eyebrow">Action</p>
<h3 id="popupTitle">Confirm action</h3>
</div>
<button id="popupClose" type="button" class="icon-button">Close</button>
</div>
<div class="popup-content">
<p id="popupDescription" class="subtitle">Please confirm this action.</p>
<label id="popupField" class="field hidden">
<span id="popupInputLabel">Value</span>
<input id="popupInput" type="text" autocomplete="off" />
</label>
</div>
<div class="popup-actions">
<button id="popupCancel" type="button" class="secondary-action">Cancel</button>
<button id="popupConfirm" type="button">Confirm</button>
</div>
</div>
</div>
<div id="onboardingModal" class="modal-overlay hidden">
<div class="modal-card onboarding-card" role="dialog" aria-modal="true" aria-labelledby="onboardingTitle" aria-describedby="onboardingSubtitle" tabindex="-1">
<div class="modal-header">
<div class="persona-modal-heading">
<p class="eyebrow">Get started</p>
<h3 id="onboardingTitle">Where shall we start?</h3>
</div>
<button id="onboardingSkip" type="button" class="icon-button">Skip</button>
</div>
<p id="onboardingSubtitle" class="subtitle">Ask a question, explore an idea, or step into a story.</p>
<div id="onboardingChoices" class="onboarding-choices"></div>
<div class="popup-actions">
<button id="onboardingBack" type="button" class="secondary-action hidden">Back</button>
<button id="onboardingContinue" type="button">Continue</button>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/marked/15.0.12/marked.min.js"
integrity="sha512-rCQgmUulW6f6QegOvTntKKb5IAoxTpGVCdWqYjkXEpzAns6XUFs8NKVqWe+KQpctp/EoRSFSuykVputqknLYMg=="
crossorigin="anonymous" defer></script>
<script src="/vendor/dompurify.js" defer></script>
<script type="module" src="/js/script.js?v=20261008-conversation-search"></script>
<script type="module" src="/js/workspaceNavigation.js?v=20260909-account-controls"></script>
</body>
</html>