This commit is contained in:
Frederik Spirgi
2026-09-09 08:50:47 +02:00
parent da51bd88e6
commit 1ed0226b69
14 changed files with 80 additions and 57 deletions
+7 -6
View File
@@ -6,11 +6,12 @@ export const onboardingPrompts = {
roleplay: ["Start a roleplay scene with immediate tension.", "Give me a dramatic opening with clear stakes."]
};
// Stable keys preserve existing saved appearance preferences.
export const themes = {
"fakegpt": {name: "FakeGPT", short: "FG"},
"fraud": {name: "Fraud", short: "FR"},
"germini": {name: "Germini", short: "GE"},
"slopilot": {name: "Slopilot", short: "SP"},
"beta-ai": {name: "Beta AI", short: "BA"},
"confusity": {name: "Confusity", short: "CF"}
"fakegpt": {name: "Grove", short: "GR"},
"fraud": {name: "Parchment", short: "PA"},
"germini": {name: "Aurora", short: "AU"},
"slopilot": {name: "Current", short: "CU"},
"beta-ai": {name: "Iris", short: "IR"},
"confusity": {name: "Graphite", short: "GP"}
};
+4 -4
View File
@@ -112,8 +112,8 @@ const onboardingContinue = $("onboardingContinue");
const onboardingSkip = $("onboardingSkip");
const authScreens = document.querySelectorAll(".auth-screen");
const toggleButtons = document.querySelectorAll(".auth-toggle .toggle");
const themeNameTargets = document.querySelectorAll("[data-theme-name]");
const themeLogoTargets = document.querySelectorAll("[data-theme-logo]");
const brandNameTargets = document.querySelectorAll("[data-brand-name]");
const brandLogoTargets = document.querySelectorAll("[data-brand-logo]");
const modelSection = document.querySelector(".chat-drawer-section--model");
const personaSection = document.querySelector(".chat-drawer-section--persona");
@@ -231,8 +231,8 @@ export {
sendBtn,
saveGenerationSettingsBtn,
sessionUser,
themeLogoTargets,
themeNameTargets,
brandLogoTargets,
brandNameTargets,
toggleButtons,
userPersonaList
};
+6 -4
View File
@@ -24,16 +24,17 @@ export function applyTheme(themeKey, {
persist = true,
title = null,
themeSelect = null,
nameTargets = document.querySelectorAll("[data-theme-name]"),
logoTargets = document.querySelectorAll("[data-theme-logo]")
nameTargets = document.querySelectorAll("[data-brand-name]"),
logoTargets = document.querySelectorAll("[data-brand-logo]")
} = {}) {
const nextTheme = normalizeTheme(themeKey);
const theme = themes[nextTheme];
document.documentElement.dataset.theme = nextTheme;
document.body.dataset.theme = nextTheme;
if (typeof title === "function") document.title = title(theme);
if (typeof title === "string") document.title = title;
nameTargets.forEach((target) => { target.textContent = theme.name; });
logoTargets.forEach((target) => { target.textContent = theme.short; });
nameTargets.forEach((target) => { target.textContent = "elsewhere"; });
logoTargets.forEach((target) => { target.textContent = ""; target.classList.add("doorway-mark"); });
if (themeSelect) themeSelect.value = nextTheme;
if (persist) localStorage.setItem(THEME_STORAGE_KEY, nextTheme);
document.dispatchEvent(new CustomEvent("appearancechange", {detail: {theme: nextTheme}}));
@@ -42,6 +43,7 @@ export function applyTheme(themeKey, {
export function applyThemeMode(modeKey, {persist = true, modeSelect = null} = {}) {
const nextMode = normalizeThemeMode(modeKey);
document.documentElement.dataset.themeMode = nextMode;
document.body.dataset.themeMode = nextMode;
if (modeSelect) modeSelect.value = nextMode;
if (persist) localStorage.setItem(THEME_MODE_STORAGE_KEY, nextMode);
+10 -8
View File
@@ -2,12 +2,13 @@
<html lang="en">
<head>
<meta charset="UTF-8"/>
<title>FakeGPT</title>
<link rel="icon" type="image/svg+xml" href="/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="app/theme-bootstrap.js"></script>
<link rel="stylesheet" href="style.css?v=20260809-2"/>
<link rel="stylesheet" href="style.css?v=20260909-elsewhere"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body data-theme="fakegpt" data-theme-mode="light">
@@ -15,10 +16,11 @@
<section id="auth" class="card auth-card auth-card-compact">
<div class="auth-hero auth-hero-compact">
<div class="brand">
<div class="logo logo-placeholder" aria-hidden="true"></div>
<div class="logo doorway-mark" aria-hidden="true"></div>
<div>
<p class="eyebrow">Private workspace</p>
<h1 data-theme-name>FakeGPT</h1>
<p class="eyebrow">Your conversation space</p>
<h1 class="brand-wordmark" data-brand-name>elsewhere</h1>
<p class="brand-tagline">A space for every conversation.</p>
</div>
</div>
</div>
@@ -80,7 +82,7 @@
<div class="sidebar-workspace-card">
<div>
<p class="eyebrow">Workspace</p>
<h2 data-theme-name>FakeGPT</h2>
<h2 class="brand-wordmark" data-brand-name>elsewhere</h2>
<p id="sessionUser" class="sidebar-account-name">Signed out</p>
</div>
<div class="sidebar-header-actions sidebar-workspace-actions">
@@ -409,11 +411,11 @@
<div class="modal-header">
<div class="persona-modal-heading">
<p class="eyebrow">Get started</p>
<h3 id="onboardingTitle">What do you want to do?</h3>
<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">Pick one path to set up your first successful chat.</p>
<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>
+4 -3
View File
@@ -2,12 +2,13 @@
<html lang="en">
<head>
<meta charset="UTF-8"/>
<title>FakeGPT Market</title>
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
<title>Elsewhere Market</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="app/theme-bootstrap.js"></script>
<link rel="stylesheet" href="style.css?v=20260809-2"/>
<link rel="stylesheet" href="style.css?v=20260909-elsewhere"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body data-theme="fakegpt" data-theme-mode="light">
@@ -15,7 +16,7 @@
<header class="market-header market-header-simple">
<div>
<p class="eyebrow">Shared personas</p>
<h1><span data-theme-name>FakeGPT</span> Market</h1>
<h1><span class="brand-wordmark" data-brand-name>elsewhere</span> Market</h1>
</div>
<div class="market-header-actions">
<button id="refreshMarket" class="secondary-action" type="button">Refresh</button>
+2 -2
View File
@@ -59,7 +59,7 @@ const marketPopupDescription = $("marketPopupDescription");
const marketPopupField = $("marketPopupField");
const marketPopupInputLabel = $("marketPopupInputLabel");
const marketPopupInput = $("marketPopupInput");
const themeNameTargets = document.querySelectorAll("[data-theme-name]");
const brandNameTargets = document.querySelectorAll("[data-brand-name]");
const marketPersonaFields = {
name: marketPersonaName,
pronouns: marketPersonaPronouns,
@@ -673,7 +673,7 @@ marketPersonaForm.addEventListener("submit", (event) => {
});
window.addEventListener("load", async () => {
initializeAppearance({title: (theme) => `${theme.name} Market`, nameTargets: themeNameTargets});
initializeAppearance({title: "Elsewhere Market", nameTargets: brandNameTargets});
const params = new URLSearchParams(window.location.search);
setMarketSort("assistant", params.get("assistantSort") || "best", {reload: false});
setMarketSort("user", params.get("userSort") || "best", {reload: false});
+1
View File
@@ -1,6 +1,7 @@
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Privacy Policy – DeepFake</title>
+8 -8
View File
@@ -111,8 +111,8 @@ import {
sendBtn,
saveGenerationSettingsBtn,
sessionUser,
themeLogoTargets,
themeNameTargets,
brandLogoTargets,
brandNameTargets,
toggleButtons,
userPersonaList
} from "./app/dom.js";
@@ -227,8 +227,8 @@ function renderOnboardingStep() {
onboardingBack.classList.toggle("hidden", onboardingStep === 1);
onboardingContinue.classList.toggle("hidden", onboardingStep === 2);
if (onboardingStep === 1) {
onboardingTitle.textContent = "What do you want to do?";
onboardingSubtitle.textContent = "Choose one path. You can switch anytime.";
onboardingTitle.textContent = "Where shall we start?";
onboardingSubtitle.textContent = "Ask a question, explore an idea, or step into a story.";
[["ask", "Ask questions"], ["brainstorm", "Brainstorm ideas"], ["roleplay", "Roleplay with a character"]].forEach(([key, label]) => {
const button = document.createElement("button");
button.type = "button";
@@ -812,7 +812,7 @@ function renderMessageEmptyState() {
actions.className = "messages-empty-actions";
if (!chat) {
title.textContent = "Start a chat";
title.textContent = "Where shall we start?";
description.textContent = "Choose a starting point.";
actions.append(
createStarterAction("New chat", "primary-action", () => { void createNewChat(); }),
@@ -951,9 +951,9 @@ function updateModelHelp() {
function applyTheme(themeKey, persist = true) {
applySharedTheme(themeKey, {
persist,
title: (theme) => theme.name,
nameTargets: themeNameTargets,
logoTargets: themeLogoTargets
title: "Elsewhere",
nameTargets: brandNameTargets,
logoTargets: brandLogoTargets
});
updateWorkspaceCopy();
renderModelSection();
+14 -13
View File
@@ -1,20 +1,21 @@
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
<meta charset="UTF-8"/>
<title>Settings</title>
<title>Elsewhere Settings</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="app/theme-bootstrap.js"></script>
<link rel="stylesheet" href="style.css?v=20260809-2"/>
<link rel="stylesheet" href="style.css?v=20260909-elsewhere"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body data-theme="fakegpt" data-theme-mode="light">
<div class="settings-shell card">
<header class="market-header market-header-simple">
<div>
<p class="eyebrow">Settings</p>
<p class="eyebrow">Elsewhere settings</p>
<h1>Preferences</h1>
</div>
<div class="market-header-actions">
@@ -135,24 +136,24 @@
<div class="settings-section-header">
<div>
<p class="eyebrow">Appearance</p>
<h2>Theme</h2>
<p class="subtitle">Themes are only changed here.</p>
<h2>Make yourself at home</h2>
<p class="subtitle">Choose a style for your conversation space.</p>
</div>
</div>
<div class="settings-theme-row">
<label class="field">
<span>Theme</span>
<span>Style</span>
<select id="settingsThemeSelect">
<option value="fakegpt">FakeGPT</option>
<option value="fraud">Fraud</option>
<option value="germini">Germini</option>
<option value="slopilot">Slopilot</option>
<option value="beta-ai">Beta AI</option>
<option value="confusity">Confusity</option>
<option value="fakegpt">Grove</option>
<option value="fraud">Parchment</option>
<option value="germini">Aurora</option>
<option value="slopilot">Current</option>
<option value="beta-ai">Iris</option>
<option value="confusity">Graphite</option>
</select>
</label>
<label class="field">
<span>Theme mode</span>
<span>Light or dark</span>
<select id="themeModeSelect">
<option value="light">Light</option>
<option value="dark">Dark</option>
+4 -4
View File
@@ -127,7 +127,7 @@ function promptSettingsPopup({
}
function applyTheme(themeKey, persist = true) {
return applySharedTheme(themeKey, {persist, title: "Settings", themeSelect: settingsThemeSelect});
return applySharedTheme(themeKey, {persist, title: "Elsewhere Settings", themeSelect: settingsThemeSelect});
}
function applyThemeMode(modeKey, persist = true) {
@@ -526,11 +526,11 @@ passwordForm.addEventListener("submit", async (event) => {
settingsThemeSelect.addEventListener("change", (event) => {
applyTheme(event.target.value);
setNotice("Theme updated.", "success");
setNotice("Style updated.", "success");
});
themeModeSelect.addEventListener("change", (event) => {
applyThemeMode(event.target.value);
setNotice(`Theme mode set to ${document.body.dataset.themeMode}.`, "success");
setNotice(`Appearance set to ${document.body.dataset.themeMode}.`, "success");
});
workspaceModeSelect.addEventListener("change", (event) => {
const mode = event.target.value === "advanced" ? "advanced" : "basic";
@@ -572,7 +572,7 @@ settingsPopupInput.addEventListener("keydown", (event) => {
});
window.addEventListener("load", async () => {
initializeAppearance({title: "Settings", themeSelect: settingsThemeSelect, modeSelect: themeModeSelect});
initializeAppearance({title: "Elsewhere Settings", themeSelect: settingsThemeSelect, modeSelect: themeModeSelect});
workspaceModeSelect.value = localStorage.getItem("krishd-workspace-mode") || "basic";
const params = new URLSearchParams(window.location.search);
const view = params.get("view") || "personal";
+8 -1
View File
@@ -1,4 +1,4 @@
/* KrisHD AI design system — rebuilt from scratch. */
/* Elsewhere design system. */
/* ---------- Foundation ---------- */
:root {
@@ -611,3 +611,10 @@ input:focus, textarea:focus, select:focus { border-color: var(--brand); }
@keyframes loading-bar { 0%, 100% { height: 7px; opacity: .45; } 50% { height: 18px; opacity: 1; } }
@keyframes pulse { 50% { opacity: .35; } }
@keyframes wave { 50% { height: 28px; } }
/* Permanent Elsewhere identity, shared by every appearance style. */
.brand-wordmark { font-family: "Manrope", "Segoe UI", sans-serif; font-weight: 700; letter-spacing: -.055em; }
.brand-tagline { margin: 12px 0 0; color: var(--text-soft); font-size: .95rem; }
.doorway-mark { position: relative; flex-shrink: 0; }
.doorway-mark::before { content: ""; width: 22px; height: 30px; border: 2px solid currentColor; border-bottom: 0; border-radius: 10px 10px 0 0; }
.doorway-mark::after { content: ""; position: absolute; width: 13px; height: 25px; left: calc(50% - 10px); top: calc(50% - 8px); border: 2px solid currentColor; background: var(--brand); transform: skewY(-18deg); transform-origin: left top; }
+1
View File
@@ -1,6 +1,7 @@
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Terms of Service – DeepFake</title>