Remove vite-ssg temp from tracking

This commit is contained in:
Nico 2026-04-01 00:17:51 +02:00
parent bf047d1292
commit 4718feb773
14 changed files with 1 additions and 6607 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
node_modules node_modules
dist dist
.env.local .env.local
.vite-ssg-temp

File diff suppressed because it is too large Load Diff

View File

@ -1,66 +0,0 @@
import { resolveComponent, mergeProps, withCtx, createTextVNode, useSSRContext } from "vue";
import { ssrRenderAttrs, ssrRenderComponent } from "vue/server-renderer";
import { _ as _export_sfc } from "../main.mjs";
import "@unhead/vue/server";
import "vue-router";
import "pinia";
import "@heroicons/vue/24/outline";
import "@heroicons/vue/20/solid";
import "overlayscrollbars-vue";
import "overlayscrollbars";
const _sfc_main = {};
function _sfc_ssrRender(_ctx, _push, _parent, _attrs) {
const _component_router_link = resolveComponent("router-link");
_push(`<div${ssrRenderAttrs(mergeProps({ class: "company-page" }, _attrs))} data-v-7d8ccc13><div class="hero" data-v-7d8ccc13><h1 data-v-7d8ccc13>Wir bauen<br data-v-7d8ccc13>agentische <em data-v-7d8ccc13>Produkte</em>.</h1><p data-v-7d8ccc13>Eigene Plattform. Eigene Infrastruktur. Eigene Regeln.</p></div><hr class="divider" data-v-7d8ccc13><section id="plattform" data-v-7d8ccc13><div class="section-label" data-v-7d8ccc13>Plattform</div><h2 data-v-7d8ccc13>Was dahintersteht.</h2><div class="cards" data-v-7d8ccc13><div class="card" data-v-7d8ccc13><h3 data-v-7d8ccc13>Das Wesentliche</h3><p data-v-7d8ccc13>Jedes Produkt kennt seinen Bereich und bleibt darin. Tiefe schlägt Breite — verlässlich, jeden Tag. Keine Extras, die niemand braucht.</p></div><div class="card" data-v-7d8ccc13><h3 data-v-7d8ccc13>Produkte für Teams</h3><p data-v-7d8ccc13>Ein Produkt für das ganze Team. Alle arbeiten mit demselben Zugang — in eigenen Sitzungen, mit voller Kontrolle darüber, wer was sieht.</p></div><div class="card" data-v-7d8ccc13><h3 data-v-7d8ccc13>Sicher &amp; konform</h3><p data-v-7d8ccc13>Alle Daten liegen in Deutschland. Mandantentrennung auf Containerebene, DSGVO-konforme Verarbeitung, Auftragsverarbeitung inklusive.</p></div></div></section><hr class="divider" data-v-7d8ccc13><section id="produkte" data-v-7d8ccc13><div class="section-label" data-v-7d8ccc13>Produkte</div><h2 data-v-7d8ccc13>Woran wir gerade bauen.</h2><div class="cards" data-v-7d8ccc13><div class="card" data-v-7d8ccc13><h3 data-v-7d8ccc13>Frühkindliche Bildung</h3><p data-v-7d8ccc13>Fachkräfte sagen, was sie brauchen — unser Produkt baut daraus fertige Bildungsangebote. Passend zur Einrichtung, zur Altersgruppe, zum Alltag.</p></div><div class="card" data-v-7d8ccc13><h3 data-v-7d8ccc13>Erwachsenen-Grundbildung</h3><p data-v-7d8ccc13>Lehrkräfte an Bildungseinrichtungen bekommen Unterstützung bei der Erstellung von Lernangeboten — strukturiert, lehrplannah, sofort einsetzbar.</p></div></div></section><hr class="divider" data-v-7d8ccc13><div class="cta" data-v-7d8ccc13><h2 data-v-7d8ccc13>nyx</h2><p data-v-7d8ccc13>Produkte kennenlernen, ausprobieren, Zugang einrichten — direkt hier, direkt mit nyx.</p>`);
_push(ssrRenderComponent(_component_router_link, {
to: "/agents",
class: "btn"
}, {
default: withCtx((_, _push2, _parent2, _scopeId) => {
if (_push2) {
_push2(`nyx öffnen`);
} else {
return [
createTextVNode("nyx öffnen")
];
}
}),
_: 1
}, _parent));
_push(`</div><footer data-v-7d8ccc13><div class="footer-links" data-v-7d8ccc13>`);
_push(ssrRenderComponent(_component_router_link, { to: "/impressum" }, {
default: withCtx((_, _push2, _parent2, _scopeId) => {
if (_push2) {
_push2(`Impressum`);
} else {
return [
createTextVNode("Impressum")
];
}
}),
_: 1
}, _parent));
_push(ssrRenderComponent(_component_router_link, { to: "/datenschutz" }, {
default: withCtx((_, _push2, _parent2, _scopeId) => {
if (_push2) {
_push2(`Datenschutz`);
} else {
return [
createTextVNode("Datenschutz")
];
}
}),
_: 1
}, _parent));
_push(`</div><span data-v-7d8ccc13>© 2026 loop42 UG (haftungsbeschränkt)</span></footer></div>`);
}
const _sfc_setup = _sfc_main.setup;
_sfc_main.setup = (props, ctx) => {
const ssrContext = useSSRContext();
(ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("src/views/CompanyView.vue");
return _sfc_setup ? _sfc_setup(props, ctx) : void 0;
};
const CompanyView = /* @__PURE__ */ _export_sfc(_sfc_main, [["ssrRender", _sfc_ssrRender], ["__scopeId", "data-v-7d8ccc13"]]);
export {
CompanyView as default
};

View File

@ -1,50 +0,0 @@
import { resolveComponent, mergeProps, withCtx, createTextVNode, useSSRContext } from "vue";
import { ssrRenderAttrs, ssrRenderComponent } from "vue/server-renderer";
import { _ as _export_sfc } from "../main.mjs";
import "@unhead/vue/server";
import "vue-router";
import "pinia";
import "@heroicons/vue/24/outline";
import "@heroicons/vue/20/solid";
import "overlayscrollbars-vue";
import "overlayscrollbars";
const _sfc_main = {};
function _sfc_ssrRender(_ctx, _push, _parent, _attrs) {
const _component_router_link = resolveComponent("router-link");
_push(`<div${ssrRenderAttrs(mergeProps({ class: "legal-page" }, _attrs))} data-v-2cc9352e><h1 data-v-2cc9352e>Datenschutzerklärung</h1><h2 data-v-2cc9352e>1. Verantwortlicher</h2><p data-v-2cc9352e> loop42 UG (haftungsbeschränkt)<br data-v-2cc9352e> [NAME]<br data-v-2cc9352e> [STRASSE HAUSNUMMER], [PLZ ORT] </p><h2 data-v-2cc9352e>2. Erhebung und Speicherung personenbezogener Daten</h2><p data-v-2cc9352e> Beim Besuch dieser Website werden automatisch Informationen allgemeiner Natur erfasst (sog. Server-Logfiles). Diese umfassen u. a. den Browsertyp, das verwendete Betriebssystem, den Referrer, die IP-Adresse sowie Datum und Uhrzeit des Zugriffs. Diese Daten sind nicht bestimmten Personen zuordbar und werden nicht mit anderen Datenquellen zusammengeführt. </p><p data-v-2cc9352e> Eine darüber hinausgehende Erhebung personenbezogener Daten findet auf dieser Website derzeit nicht statt. Sobald weitere Dienste (z. B. Kontaktformular, Nutzerkonten) eingeführt werden, wird diese Erklärung entsprechend aktualisiert. </p><h2 data-v-2cc9352e>3. Hosting und Infrastruktur</h2><p data-v-2cc9352e> Diese Website wird auf einem Server in einem deutschen Rechenzentrum betrieben. Der Anbieter ist IONOS SE, Elgendorfer Str. 57, 56410 Montabaur, Deutschland. Weitere Informationen zum Datenschutz bei IONOS finden Sie unter <a href="https://www.ionos.de/terms-gtc/datenschutzerklaerung/" target="_blank" rel="noopener" data-v-2cc9352e>ionos.de</a>. </p><h2 data-v-2cc9352e>4. Cookies</h2><p data-v-2cc9352e>Diese Website verwendet keine Cookies.</p><h2 data-v-2cc9352e>5. Analyse-Tools und Tracking</h2><p data-v-2cc9352e> Diese Website verwendet keine Analyse-Tools, kein Tracking und keine eingebetteten Inhalte Dritter (z. B. Google Fonts, Social-Media-Widgets). Es werden keine Daten an Dritte übermittelt. </p><h2 data-v-2cc9352e>6. Ihre Rechte</h2><p data-v-2cc9352e>Sie haben gegenüber uns folgende Rechte hinsichtlich Ihrer personenbezogenen Daten:</p><ul data-v-2cc9352e><li data-v-2cc9352e>Recht auf Auskunft (Art. 15 DSGVO)</li><li data-v-2cc9352e>Recht auf Berichtigung (Art. 16 DSGVO)</li><li data-v-2cc9352e>Recht auf Löschung (Art. 17 DSGVO)</li><li data-v-2cc9352e>Recht auf Einschränkung der Verarbeitung (Art. 18 DSGVO)</li><li data-v-2cc9352e>Recht auf Datenübertragbarkeit (Art. 20 DSGVO)</li><li data-v-2cc9352e>Recht auf Widerspruch gegen die Verarbeitung (Art. 21 DSGVO)</li></ul><p data-v-2cc9352e>Zur Ausübung Ihrer Rechte wenden Sie sich bitte an: [E-MAIL]</p><h2 data-v-2cc9352e>7. Beschwerderecht bei der Aufsichtsbehörde</h2><p data-v-2cc9352e> Sie haben das Recht, sich bei einer Datenschutz-Aufsichtsbehörde über die Verarbeitung Ihrer personenbezogenen Daten durch uns zu beschweren. Die zuständige Aufsichtsbehörde richtet sich nach dem Bundesland des Unternehmenssitzes. </p><h2 data-v-2cc9352e>8. Aktualität und Änderungen</h2><p data-v-2cc9352e> Diese Datenschutzerklärung ist aktuell gültig und hat den Stand März 2026. Durch die Weiterentwicklung unserer Website oder aufgrund geänderter gesetzlicher Vorgaben kann es notwendig werden, diese Datenschutzerklärung anzupassen. </p><footer data-v-2cc9352e><div class="footer-links" data-v-2cc9352e>`);
_push(ssrRenderComponent(_component_router_link, { to: "/impressum" }, {
default: withCtx((_, _push2, _parent2, _scopeId) => {
if (_push2) {
_push2(`Impressum`);
} else {
return [
createTextVNode("Impressum")
];
}
}),
_: 1
}, _parent));
_push(ssrRenderComponent(_component_router_link, { to: "/datenschutz" }, {
default: withCtx((_, _push2, _parent2, _scopeId) => {
if (_push2) {
_push2(`Datenschutz`);
} else {
return [
createTextVNode("Datenschutz")
];
}
}),
_: 1
}, _parent));
_push(`</div><span data-v-2cc9352e>© 2026 loop42 UG (haftungsbeschränkt)</span></footer></div>`);
}
const _sfc_setup = _sfc_main.setup;
_sfc_main.setup = (props, ctx) => {
const ssrContext = useSSRContext();
(ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("src/views/DatenschutzView.vue");
return _sfc_setup ? _sfc_setup(props, ctx) : void 0;
};
const DatenschutzView = /* @__PURE__ */ _export_sfc(_sfc_main, [["ssrRender", _sfc_ssrRender], ["__scopeId", "data-v-2cc9352e"]]);
export {
DatenschutzView as default
};

View File

@ -1,738 +0,0 @@
import { defineComponent, ref, computed, onMounted, nextTick, watch, onUnmounted, resolveComponent, unref, mergeProps, withCtx, createVNode, createTextVNode, resolveDynamicComponent, openBlock, createBlock, withDirectives, vModelCheckbox, toDisplayString, createCommentVNode, Fragment, renderList, Teleport, withModifiers, useSSRContext } from "vue";
import { ssrRenderComponent, ssrIncludeBooleanAttr, ssrRenderClass, ssrRenderVNode, ssrLooseContain, ssrRenderStyle, ssrInterpolate, ssrRenderList, ssrRenderTeleport, ssrRenderAttrs } from "vue/server-renderer";
import { useRoute } from "vue-router";
import { t as takeover, g as getApiBase, w as ws, b as auth, s as scrollbarOptions, T as THEME_ICONS, f as useTheme, h as useDevFlags, _ as _export_sfc } from "../main.mjs";
import { OverlayScrollbarsComponent } from "overlayscrollbars-vue";
import { HomeIcon, BoltIcon, SignalSlashIcon, LinkIcon, XMarkIcon, CameraIcon, LockClosedIcon } from "@heroicons/vue/20/solid";
import "@unhead/vue/server";
import "pinia";
import "@heroicons/vue/24/outline";
import "overlayscrollbars";
const SESSION_KEY = "nyx_session";
const _sfc_main = /* @__PURE__ */ defineComponent({
...{ name: "DevView" },
__name: "DevView",
__ssrInlineRender: true,
setup(__props) {
const route = useRoute();
const { isLoggedIn } = auth;
const { connected, send: wsSend, onMessage } = ws;
const { theme, setTheme } = useTheme();
const devFlags = useDevFlags();
const takeoverToken = takeover.token;
const captureActive = takeover.capture.isActive;
const breakoutReq = takeover.breakout.pendingRequest;
function handleInitTakeover() {
takeover.init();
}
function handleRevoke() {
takeover.revoke();
}
function confirmBreakout() {
breakoutReq.value?.resolve(true);
}
function denyBreakout() {
breakoutReq.value?.resolve(false);
}
async function handleToggleCapture() {
if (captureActive.value) {
takeover.capture.disable();
} else {
await takeover.capture.enable();
}
}
const SESSION_TOKEN = () => localStorage.getItem(SESSION_KEY) ?? "";
const systemRequests = ref([]);
const systemGranted = ref(null);
async function fetchPendingSystemRequests() {
try {
const res = await fetch(`${getApiBase()}/api/system/pending`, {
headers: { Authorization: `Bearer ${SESSION_TOKEN()}` }
});
if (res.ok) {
const { pending } = await res.json();
systemRequests.value = pending ?? [];
}
} catch {
}
}
async function approveSystemRequest(requestId) {
const res = await fetch(`${getApiBase()}/api/system/approve`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ sessionToken: SESSION_TOKEN(), requestId })
});
if (res.ok) systemRequests.value = systemRequests.value.filter((r) => r.requestId !== requestId);
}
async function denySystemRequest(requestId) {
await fetch(`${getApiBase()}/api/system/deny`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ sessionToken: SESSION_TOKEN(), requestId })
});
systemRequests.value = systemRequests.value.filter((r) => r.requestId !== requestId);
}
const counterValue = ref(Math.floor(Math.random() * 11));
const counterBusy = ref(false);
const counterMuted = ref(true);
const challengeMessage = ref("");
const challengeTimer = ref(0);
let challengeInterval = null;
let challengeGen = 0;
const actionPicker = ref({ title: "", options: [] });
const actionPickerBusy = ref(false);
async function pickAction(id) {
actionPickerBusy.value = true;
actionPicker.value = { title: "", options: [] };
try {
await fetch(`${getApiBase()}/api/dev/counter`, {
method: "POST",
headers: { "Content-Type": "application/json", Authorization: `Bearer ${SESSION_TOKEN()}` },
body: JSON.stringify({ action: "pick", pick: id })
});
} catch {
}
actionPickerBusy.value = false;
}
async function counterAction(action) {
counterMuted.value = true;
challengeGen++;
if (challengeInterval) {
clearInterval(challengeInterval);
challengeInterval = null;
}
challengeMessage.value = "";
challengeTimer.value = 0;
counterBusy.value = true;
try {
await fetch(`${getApiBase()}/api/dev/counter`, {
method: "POST",
headers: { "Content-Type": "application/json", Authorization: `Bearer ${SESSION_TOKEN()}` },
body: JSON.stringify({ action })
});
} catch {
}
counterBusy.value = false;
}
const loading = ref(false);
const statsError = ref("");
const stats = ref(null);
function fmt(v) {
if (v === null || v === void 0) return "—";
return v.toFixed(2);
}
const usedPct = computed(() => {
const t = stats.value?.credits?.total;
const u = stats.value?.credits?.used;
if (!t) return 0;
return Math.min(100, u / t * 100);
});
function load() {
if (!connected.value) return;
loading.value = true;
statsError.value = "";
wsSend({ type: "stats_request" });
}
const discoing = ref(false);
const discoChatting = ref(false);
function disco() {
if (!connected.value) return;
discoing.value = true;
wsSend({ type: "disco_request" });
setTimeout(() => {
discoing.value = false;
}, 2e3);
}
function discoChat() {
if (!connected.value) return;
discoChatting.value = true;
wsSend({ type: "disco_chat_request" });
setTimeout(() => {
discoChatting.value = false;
}, 3e3);
}
let unsubscribeWs = null;
let refreshInterval;
onMounted(() => {
fetchPendingSystemRequests();
unsubscribeWs = onMessage((data) => {
if (data.type === "system_access_request") {
if (!systemRequests.value.find((r) => r.requestId === data.requestId))
systemRequests.value.push(data);
return;
}
if (data.type === "counter_update") {
counterValue.value = data.value ?? counterValue.value;
return;
}
if (data.type === "counter_challenge") {
challengeMessage.value = data.message || "DECIDE NOW!";
challengeTimer.value = data.timeout || 30;
counterMuted.value = false;
nextTick(() => {
const el = document.querySelector(".counter-widget");
if (el) {
el.classList.remove("flash");
void el.offsetWidth;
el.classList.add("flash");
el.scrollIntoView({ behavior: "smooth", block: "center" });
}
});
if (challengeInterval) clearInterval(challengeInterval);
const cid = ++challengeGen;
challengeInterval = setInterval(() => {
if (cid !== challengeGen) {
clearInterval(challengeInterval);
return;
}
challengeTimer.value--;
if (challengeTimer.value <= 0) {
if (challengeInterval) {
clearInterval(challengeInterval);
challengeInterval = null;
}
counterMuted.value = true;
challengeMessage.value = "";
fetch(`${getApiBase()}/api/dev/counter`, {
method: "POST",
headers: { "Content-Type": "application/json", Authorization: `Bearer ${SESSION_TOKEN()}` },
body: JSON.stringify({ action: "timeout" })
});
}
}, 1e3);
return;
}
if (data.type === "confetti") {
const container = document.createElement("div");
container.className = "confetti-container";
const colors = ["#ff6b6b", "#ffd93d", "#6bcb77", "#4d96ff", "#ff922b", "#cc5de8"];
for (let i = 0; i < 60; i++) {
const piece = document.createElement("div");
piece.className = "confetti-piece";
piece.style.left = Math.random() * 100 + "%";
piece.style.background = colors[Math.floor(Math.random() * colors.length)];
piece.style.animationDelay = Math.random() * 2 + "s";
piece.style.borderRadius = Math.random() > 0.5 ? "50%" : "0";
container.appendChild(piece);
}
document.body.appendChild(container);
setTimeout(() => container.remove(), 5e3);
return;
}
if (data.type === "action_picker") {
actionPicker.value = { title: data.title || "Next?", options: data.options || [] };
actionPickerBusy.value = false;
return;
}
if (data.type === "counter_mute") {
counterMuted.value = true;
challengeMessage.value = data.message || "";
if (challengeInterval) {
clearInterval(challengeInterval);
challengeInterval = null;
}
challengeTimer.value = 0;
return;
}
if (data.type === "stats") {
loading.value = false;
if (data.error) {
statsError.value = data.error;
} else {
stats.value = data;
}
}
});
const startRefresh = () => {
load();
refreshInterval = setInterval(load, 15e3);
};
if (connected.value) {
startRefresh();
} else {
const stop = watch(connected, (val) => {
if (val) {
stop();
startRefresh();
}
});
}
});
watch(() => route.name, (name, prev) => {
if (name === "dev" && !refreshInterval && connected.value) {
load();
refreshInterval = setInterval(load, 15e3);
} else if (prev === "dev" && name !== "dev" && refreshInterval) {
clearInterval(refreshInterval);
refreshInterval = void 0;
}
});
onUnmounted(() => {
if (unsubscribeWs) unsubscribeWs();
if (refreshInterval) clearInterval(refreshInterval);
});
return (_ctx, _push, _parent, _attrs) => {
const _component_RouterLink = resolveComponent("RouterLink");
if (unref(isLoggedIn)) {
_push(ssrRenderComponent(unref(OverlayScrollbarsComponent), mergeProps({
class: "dev-view",
options: unref(scrollbarOptions),
element: "div"
}, _attrs), {
default: withCtx((_, _push2, _parent2, _scopeId) => {
if (_push2) {
_push2(`<div class="page" data-v-6fcff79f${_scopeId}><div class="dev-header" data-v-6fcff79f${_scopeId}><h2 data-v-6fcff79f${_scopeId}>/dev</h2><div class="dev-actions" data-v-6fcff79f${_scopeId}>`);
_push2(ssrRenderComponent(_component_RouterLink, {
to: "/agents",
class: "dev-disco-btn"
}, {
default: withCtx((_2, _push3, _parent3, _scopeId2) => {
if (_push3) {
_push3(ssrRenderComponent(unref(HomeIcon), { class: "w-4 h-4 inline" }, null, _parent3, _scopeId2));
_push3(` Home`);
} else {
return [
createVNode(unref(HomeIcon), { class: "w-4 h-4 inline" }),
createTextVNode(" Home")
];
}
}),
_: 1
}, _parent2, _scopeId));
_push2(`<button class="dev-disco-btn"${ssrIncludeBooleanAttr(discoing.value) ? " disabled" : ""} data-v-6fcff79f${_scopeId}>`);
_push2(ssrRenderComponent(unref(BoltIcon), { class: "w-4 h-4 inline" }, null, _parent2, _scopeId));
_push2(` Disconnect Gateway</button><button class="dev-disco-btn"${ssrIncludeBooleanAttr(discoChatting.value) ? " disabled" : ""} data-v-6fcff79f${_scopeId}>`);
_push2(ssrRenderComponent(unref(SignalSlashIcon), { class: "w-4 h-4 inline" }, null, _parent2, _scopeId));
_push2(` Disconnect Chat</button></div></div><div class="content" data-v-6fcff79f${_scopeId}><div class="dev-section" data-v-6fcff79f${_scopeId}><h3 data-v-6fcff79f${_scopeId}>Theme</h3><div class="dev-actions" data-v-6fcff79f${_scopeId}><button class="${ssrRenderClass([{ active: unref(theme) === "loop42" }, "dev-theme-btn"])}" data-v-6fcff79f${_scopeId}>`);
ssrRenderVNode(_push2, createVNode(resolveDynamicComponent(unref(THEME_ICONS).loop42), { class: "w-4 h-4 inline" }, null), _parent2, _scopeId);
_push2(` loop42</button><button class="${ssrRenderClass([{ active: unref(theme) === "titan" }, "dev-theme-btn"])}" data-v-6fcff79f${_scopeId}>`);
ssrRenderVNode(_push2, createVNode(resolveDynamicComponent(unref(THEME_ICONS).titan), { class: "w-4 h-4 inline" }, null), _parent2, _scopeId);
_push2(` Titan</button><button class="${ssrRenderClass([{ active: unref(theme) === "eras" }, "dev-theme-btn"])}" data-v-6fcff79f${_scopeId}>`);
ssrRenderVNode(_push2, createVNode(resolveDynamicComponent(unref(THEME_ICONS).eras), { class: "w-4 h-4 inline" }, null), _parent2, _scopeId);
_push2(` ERAS</button></div></div><div class="dev-section" data-v-6fcff79f${_scopeId}><h3 data-v-6fcff79f${_scopeId}>Dev Flags</h3><div class="dev-flags" data-v-6fcff79f${_scopeId}><label class="dev-flag" data-v-6fcff79f${_scopeId}><input type="checkbox"${ssrIncludeBooleanAttr(Array.isArray(unref(devFlags).showGrid) ? ssrLooseContain(unref(devFlags).showGrid, null) : unref(devFlags).showGrid) ? " checked" : ""} data-v-6fcff79f${_scopeId}><span data-v-6fcff79f${_scopeId}>showGrid</span></label><label class="dev-flag" data-v-6fcff79f${_scopeId}><input type="checkbox"${ssrIncludeBooleanAttr(Array.isArray(unref(devFlags).showDebugInfo) ? ssrLooseContain(unref(devFlags).showDebugInfo, null) : unref(devFlags).showDebugInfo) ? " checked" : ""} data-v-6fcff79f${_scopeId}><span data-v-6fcff79f${_scopeId}>showDebugInfo</span></label><label class="dev-flag" data-v-6fcff79f${_scopeId}><input type="checkbox"${ssrIncludeBooleanAttr(Array.isArray(unref(devFlags).showHud) ? ssrLooseContain(unref(devFlags).showHud, null) : unref(devFlags).showHud) ? " checked" : ""} data-v-6fcff79f${_scopeId}><span data-v-6fcff79f${_scopeId}>showHud</span></label></div></div><div class="dev-section" data-v-6fcff79f${_scopeId}><h3 data-v-6fcff79f${_scopeId}>Takeover</h3>`);
if (!unref(takeoverToken)) {
_push2(`<div class="dev-actions" data-v-6fcff79f${_scopeId}><button class="dev-theme-btn" data-v-6fcff79f${_scopeId}>`);
_push2(ssrRenderComponent(unref(LinkIcon), { class: "w-4 h-4 inline" }, null, _parent2, _scopeId));
_push2(` Enable Takeover</button></div>`);
} else {
_push2(`<div class="dev-actions" style="${ssrRenderStyle({ "gap": "var(--space-page)", "align-items": "center", "flex-wrap": "wrap" })}" data-v-6fcff79f${_scopeId}><code class="takeover-token" data-v-6fcff79f${_scopeId}>${ssrInterpolate(unref(takeoverToken))}</code><button class="dev-theme-btn active" data-v-6fcff79f${_scopeId}>`);
_push2(ssrRenderComponent(unref(XMarkIcon), { class: "w-4 h-4 inline" }, null, _parent2, _scopeId));
_push2(` Revoke</button><button class="${ssrRenderClass([{ active: unref(captureActive) }, "dev-theme-btn"])}" data-v-6fcff79f${_scopeId}>`);
_push2(ssrRenderComponent(unref(CameraIcon), { class: "w-4 h-4 inline" }, null, _parent2, _scopeId));
_push2(` ${ssrInterpolate(unref(captureActive) ? "Capture ON" : "Enable Capture")}</button></div>`);
}
_push2(`</div>`);
if (systemRequests.value.length > 0 || systemGranted.value) {
_push2(`<div class="dev-section" data-v-6fcff79f${_scopeId}><h3 data-v-6fcff79f${_scopeId}>System Access</h3>`);
if (systemGranted.value) {
_push2(`<div class="dev-system-granted" data-v-6fcff79f${_scopeId}> Access granted to ${ssrInterpolate(systemGranted.value.user)} — active until session end. </div>`);
} else {
_push2(`<!---->`);
}
_push2(`<!--[-->`);
ssrRenderList(systemRequests.value, (req) => {
_push2(`<div class="dev-system-request" data-v-6fcff79f${_scopeId}><div class="dev-system-code" data-v-6fcff79f${_scopeId}>${ssrInterpolate(req.userCode)}</div><div class="dev-system-desc" data-v-6fcff79f${_scopeId}>${ssrInterpolate(req.description)}</div><div class="dev-system-expiry" data-v-6fcff79f${_scopeId}>expires in ${ssrInterpolate(Math.max(0, Math.ceil((req.expiresAt - Date.now()) / 1e3)))}s</div><div class="dev-actions" style="${ssrRenderStyle({ "margin-top": "8px" })}" data-v-6fcff79f${_scopeId}><button class="dev-theme-btn" data-v-6fcff79f${_scopeId}>Deny</button><button class="dev-theme-btn active" data-v-6fcff79f${_scopeId}>Approve</button></div></div>`);
});
_push2(`<!--]--></div>`);
} else {
_push2(`<!---->`);
}
_push2(`<div class="dev-section" data-v-6fcff79f${_scopeId}><h3 data-v-6fcff79f${_scopeId}>MCP Counter</h3><div class="${ssrRenderClass([{ muted: counterMuted.value }, "counter-widget"])}" data-v-6fcff79f${_scopeId}><div class="counter-controls" data-v-6fcff79f${_scopeId}><button class="counter-btn"${ssrIncludeBooleanAttr(counterMuted.value || counterBusy.value) ? " disabled" : ""} data-v-6fcff79f${_scopeId}></button><span class="counter-value" id="mcp-counter-value" data-v-6fcff79f${_scopeId}>${ssrInterpolate(counterValue.value)}</span><button class="counter-btn"${ssrIncludeBooleanAttr(counterMuted.value || counterBusy.value) ? " disabled" : ""} data-v-6fcff79f${_scopeId}>+</button></div>`);
if (challengeMessage.value) {
_push2(`<div class="counter-challenge" data-v-6fcff79f${_scopeId}><span class="counter-message" data-v-6fcff79f${_scopeId}>${ssrInterpolate(challengeMessage.value)}</span>`);
if (challengeTimer.value > 0) {
_push2(`<span class="counter-timer" data-v-6fcff79f${_scopeId}>${ssrInterpolate(challengeTimer.value)}s</span>`);
} else {
_push2(`<!---->`);
}
_push2(`</div>`);
} else {
_push2(`<div class="counter-hint" data-v-6fcff79f${_scopeId}>Waiting for Claude...</div>`);
}
_push2(`</div></div>`);
if (actionPicker.value.title) {
_push2(`<div class="dev-section" data-v-6fcff79f${_scopeId}><h3 data-v-6fcff79f${_scopeId}>${ssrInterpolate(actionPicker.value.title)}</h3><div class="action-picker" data-v-6fcff79f${_scopeId}><!--[-->`);
ssrRenderList(actionPicker.value.options, (opt, i) => {
_push2(`<button class="action-pick-btn"${ssrIncludeBooleanAttr(actionPickerBusy.value) ? " disabled" : ""} data-v-6fcff79f${_scopeId}>${ssrInterpolate(opt.label)}</button>`);
});
_push2(`<!--]--></div></div>`);
} else {
_push2(`<!---->`);
}
_push2(`<div class="dev-section" data-v-6fcff79f${_scopeId}><h3 data-v-6fcff79f${_scopeId}>OpenRouter Credits</h3>`);
if (loading.value && !stats.value) {
_push2(`<div class="dev-loading" data-v-6fcff79f${_scopeId}>Loading…</div>`);
} else if (statsError.value) {
_push2(`<div class="dev-error" data-v-6fcff79f${_scopeId}>${ssrInterpolate(statsError.value)}</div>`);
} else if (stats.value) {
_push2(`<div class="credits-widget" data-v-6fcff79f${_scopeId}><div class="credits-bar-track" data-v-6fcff79f${_scopeId}><div class="credits-bar-fill" style="${ssrRenderStyle({ width: usedPct.value + "%" })}" data-v-6fcff79f${_scopeId}></div></div><div class="credits-row" data-v-6fcff79f${_scopeId}><div class="credits-stat" data-v-6fcff79f${_scopeId}><span class="credits-label" data-v-6fcff79f${_scopeId}>Used</span><span class="credits-amount credits-used" data-v-6fcff79f${_scopeId}>$${ssrInterpolate(fmt(stats.value.credits.used))}</span></div><div class="credits-stat" data-v-6fcff79f${_scopeId}><span class="credits-label" data-v-6fcff79f${_scopeId}>Remaining</span><span class="credits-amount credits-remaining" data-v-6fcff79f${_scopeId}>$${ssrInterpolate(fmt(stats.value.credits.remaining))}</span></div><div class="credits-stat" data-v-6fcff79f${_scopeId}><span class="credits-label" data-v-6fcff79f${_scopeId}>Total</span><span class="credits-amount" data-v-6fcff79f${_scopeId}>$${ssrInterpolate(fmt(stats.value.credits.total))}</span></div></div></div>`);
} else {
_push2(`<!---->`);
}
_push2(`</div>`);
if (stats.value) {
_push2(`<div class="dev-section" data-v-6fcff79f${_scopeId}><h3 data-v-6fcff79f${_scopeId}>Agents</h3><div class="dev-table-wrap" data-v-6fcff79f${_scopeId}><table class="dev-table" data-v-6fcff79f${_scopeId}><thead data-v-6fcff79f${_scopeId}><tr data-v-6fcff79f${_scopeId}><th data-v-6fcff79f${_scopeId}>Agent</th><th data-v-6fcff79f${_scopeId}>Model</th><th data-v-6fcff79f${_scopeId}>Context</th><th data-v-6fcff79f${_scopeId}>Prompt / 1M</th><th data-v-6fcff79f${_scopeId}>Completion / 1M</th></tr></thead><tbody data-v-6fcff79f${_scopeId}><!--[-->`);
ssrRenderList(stats.value.agents, (a) => {
_push2(`<tr data-v-6fcff79f${_scopeId}><td class="agent-id" data-v-6fcff79f${_scopeId}>${ssrInterpolate(a.id)}</td><td data-v-6fcff79f${_scopeId}><code data-v-6fcff79f${_scopeId}>${ssrInterpolate(a.modelId || a.model)}</code></td><td data-v-6fcff79f${_scopeId}>${ssrInterpolate(a.contextLength ? (a.contextLength / 1e3).toFixed(0) + "k" : "—")}</td><td data-v-6fcff79f${_scopeId}>${ssrInterpolate(a.promptPrice !== null ? "$" + a.promptPrice.toFixed(3) : "—")}</td><td data-v-6fcff79f${_scopeId}>${ssrInterpolate(a.completionPrice !== null ? "$" + a.completionPrice.toFixed(3) : "—")}</td></tr>`);
});
_push2(`<!--]--></tbody></table></div></div>`);
} else {
_push2(`<!---->`);
}
_push2(`</div></div>`);
ssrRenderTeleport(_push2, (_push3) => {
if (unref(breakoutReq)) {
_push3(`<div class="breakout-modal-overlay" data-v-6fcff79f${_scopeId}><div class="breakout-modal" data-v-6fcff79f${_scopeId}><h3 data-v-6fcff79f${_scopeId}>Open Breakout</h3><p data-v-6fcff79f${_scopeId}>Name: <strong data-v-6fcff79f${_scopeId}>${ssrInterpolate(unref(breakoutReq).name)}</strong></p><p data-v-6fcff79f${_scopeId}>Size: <strong data-v-6fcff79f${_scopeId}>${ssrInterpolate(unref(breakoutReq).preset)}</strong></p><p class="breakout-nonce" data-v-6fcff79f${_scopeId}>${ssrInterpolate(unref(breakoutReq).nonce)}</p><div class="breakout-modal-actions" data-v-6fcff79f${_scopeId}><button class="dev-theme-btn" data-v-6fcff79f${_scopeId}>Cancel</button><button class="dev-theme-btn active" data-v-6fcff79f${_scopeId}>Confirm</button></div></div></div>`);
} else {
_push3(`<!---->`);
}
}, "body", false, _parent2);
} else {
return [
createVNode("div", { class: "page" }, [
createVNode("div", { class: "dev-header" }, [
createVNode("h2", null, "/dev"),
createVNode("div", { class: "dev-actions" }, [
createVNode(_component_RouterLink, {
to: "/agents",
class: "dev-disco-btn"
}, {
default: withCtx(() => [
createVNode(unref(HomeIcon), { class: "w-4 h-4 inline" }),
createTextVNode(" Home")
]),
_: 1
}),
createVNode("button", {
class: "dev-disco-btn",
onClick: disco,
disabled: discoing.value
}, [
createVNode(unref(BoltIcon), { class: "w-4 h-4 inline" }),
createTextVNode(" Disconnect Gateway")
], 8, ["disabled"]),
createVNode("button", {
class: "dev-disco-btn",
onClick: discoChat,
disabled: discoChatting.value
}, [
createVNode(unref(SignalSlashIcon), { class: "w-4 h-4 inline" }),
createTextVNode(" Disconnect Chat")
], 8, ["disabled"])
])
]),
createVNode("div", { class: "content" }, [
createVNode("div", { class: "dev-section" }, [
createVNode("h3", null, "Theme"),
createVNode("div", { class: "dev-actions" }, [
createVNode("button", {
class: ["dev-theme-btn", { active: unref(theme) === "loop42" }],
onClick: ($event) => unref(setTheme)("loop42")
}, [
(openBlock(), createBlock(resolveDynamicComponent(unref(THEME_ICONS).loop42), { class: "w-4 h-4 inline" })),
createTextVNode(" loop42")
], 10, ["onClick"]),
createVNode("button", {
class: ["dev-theme-btn", { active: unref(theme) === "titan" }],
onClick: ($event) => unref(setTheme)("titan")
}, [
(openBlock(), createBlock(resolveDynamicComponent(unref(THEME_ICONS).titan), { class: "w-4 h-4 inline" })),
createTextVNode(" Titan")
], 10, ["onClick"]),
createVNode("button", {
class: ["dev-theme-btn", { active: unref(theme) === "eras" }],
onClick: ($event) => unref(setTheme)("eras")
}, [
(openBlock(), createBlock(resolveDynamicComponent(unref(THEME_ICONS).eras), { class: "w-4 h-4 inline" })),
createTextVNode(" ERAS")
], 10, ["onClick"])
])
]),
createVNode("div", { class: "dev-section" }, [
createVNode("h3", null, "Dev Flags"),
createVNode("div", { class: "dev-flags" }, [
createVNode("label", { class: "dev-flag" }, [
withDirectives(createVNode("input", {
type: "checkbox",
"onUpdate:modelValue": ($event) => unref(devFlags).showGrid = $event
}, null, 8, ["onUpdate:modelValue"]), [
[vModelCheckbox, unref(devFlags).showGrid]
]),
createVNode("span", null, "showGrid")
]),
createVNode("label", { class: "dev-flag" }, [
withDirectives(createVNode("input", {
type: "checkbox",
"onUpdate:modelValue": ($event) => unref(devFlags).showDebugInfo = $event
}, null, 8, ["onUpdate:modelValue"]), [
[vModelCheckbox, unref(devFlags).showDebugInfo]
]),
createVNode("span", null, "showDebugInfo")
]),
createVNode("label", { class: "dev-flag" }, [
withDirectives(createVNode("input", {
type: "checkbox",
"onUpdate:modelValue": ($event) => unref(devFlags).showHud = $event
}, null, 8, ["onUpdate:modelValue"]), [
[vModelCheckbox, unref(devFlags).showHud]
]),
createVNode("span", null, "showHud")
])
])
]),
createVNode("div", { class: "dev-section" }, [
createVNode("h3", null, "Takeover"),
!unref(takeoverToken) ? (openBlock(), createBlock("div", {
key: 0,
class: "dev-actions"
}, [
createVNode("button", {
class: "dev-theme-btn",
onClick: handleInitTakeover
}, [
createVNode(unref(LinkIcon), { class: "w-4 h-4 inline" }),
createTextVNode(" Enable Takeover")
])
])) : (openBlock(), createBlock("div", {
key: 1,
class: "dev-actions",
style: { "gap": "var(--space-page)", "align-items": "center", "flex-wrap": "wrap" }
}, [
createVNode("code", { class: "takeover-token" }, toDisplayString(unref(takeoverToken)), 1),
createVNode("button", {
class: "dev-theme-btn active",
onClick: handleRevoke
}, [
createVNode(unref(XMarkIcon), { class: "w-4 h-4 inline" }),
createTextVNode(" Revoke")
]),
createVNode("button", {
class: ["dev-theme-btn", { active: unref(captureActive) }],
onClick: handleToggleCapture
}, [
createVNode(unref(CameraIcon), { class: "w-4 h-4 inline" }),
createTextVNode(" " + toDisplayString(unref(captureActive) ? "Capture ON" : "Enable Capture"), 1)
], 2)
]))
]),
systemRequests.value.length > 0 || systemGranted.value ? (openBlock(), createBlock("div", {
key: 0,
class: "dev-section"
}, [
createVNode("h3", null, "System Access"),
systemGranted.value ? (openBlock(), createBlock("div", {
key: 0,
class: "dev-system-granted"
}, " Access granted to " + toDisplayString(systemGranted.value.user) + " — active until session end. ", 1)) : createCommentVNode("", true),
(openBlock(true), createBlock(Fragment, null, renderList(systemRequests.value, (req) => {
return openBlock(), createBlock("div", {
key: req.requestId,
class: "dev-system-request"
}, [
createVNode("div", { class: "dev-system-code" }, toDisplayString(req.userCode), 1),
createVNode("div", { class: "dev-system-desc" }, toDisplayString(req.description), 1),
createVNode("div", { class: "dev-system-expiry" }, "expires in " + toDisplayString(Math.max(0, Math.ceil((req.expiresAt - Date.now()) / 1e3))) + "s", 1),
createVNode("div", {
class: "dev-actions",
style: { "margin-top": "8px" }
}, [
createVNode("button", {
class: "dev-theme-btn",
onClick: ($event) => denySystemRequest(req.requestId)
}, "Deny", 8, ["onClick"]),
createVNode("button", {
class: "dev-theme-btn active",
onClick: ($event) => approveSystemRequest(req.requestId)
}, "Approve", 8, ["onClick"])
])
]);
}), 128))
])) : createCommentVNode("", true),
createVNode("div", { class: "dev-section" }, [
createVNode("h3", null, "MCP Counter"),
createVNode("div", {
class: ["counter-widget", { muted: counterMuted.value }]
}, [
createVNode("div", { class: "counter-controls" }, [
createVNode("button", {
class: "counter-btn",
onClick: ($event) => counterAction("decrement"),
disabled: counterMuted.value || counterBusy.value
}, "", 8, ["onClick", "disabled"]),
createVNode("span", {
class: "counter-value",
id: "mcp-counter-value"
}, toDisplayString(counterValue.value), 1),
createVNode("button", {
class: "counter-btn",
onClick: ($event) => counterAction("increment"),
disabled: counterMuted.value || counterBusy.value
}, "+", 8, ["onClick", "disabled"])
]),
challengeMessage.value ? (openBlock(), createBlock("div", {
key: 0,
class: "counter-challenge"
}, [
createVNode("span", { class: "counter-message" }, toDisplayString(challengeMessage.value), 1),
challengeTimer.value > 0 ? (openBlock(), createBlock("span", {
key: 0,
class: "counter-timer"
}, toDisplayString(challengeTimer.value) + "s", 1)) : createCommentVNode("", true)
])) : (openBlock(), createBlock("div", {
key: 1,
class: "counter-hint"
}, "Waiting for Claude..."))
], 2)
]),
actionPicker.value.title ? (openBlock(), createBlock("div", {
key: 1,
class: "dev-section"
}, [
createVNode("h3", null, toDisplayString(actionPicker.value.title), 1),
createVNode("div", { class: "action-picker" }, [
(openBlock(true), createBlock(Fragment, null, renderList(actionPicker.value.options, (opt, i) => {
return openBlock(), createBlock("button", {
key: i,
class: "action-pick-btn",
disabled: actionPickerBusy.value,
onClick: ($event) => pickAction(opt.id)
}, toDisplayString(opt.label), 9, ["disabled", "onClick"]);
}), 128))
])
])) : createCommentVNode("", true),
createVNode("div", { class: "dev-section" }, [
createVNode("h3", null, "OpenRouter Credits"),
loading.value && !stats.value ? (openBlock(), createBlock("div", {
key: 0,
class: "dev-loading"
}, "Loading…")) : statsError.value ? (openBlock(), createBlock("div", {
key: 1,
class: "dev-error"
}, toDisplayString(statsError.value), 1)) : stats.value ? (openBlock(), createBlock("div", {
key: 2,
class: "credits-widget"
}, [
createVNode("div", { class: "credits-bar-track" }, [
createVNode("div", {
class: "credits-bar-fill",
style: { width: usedPct.value + "%" }
}, null, 4)
]),
createVNode("div", { class: "credits-row" }, [
createVNode("div", { class: "credits-stat" }, [
createVNode("span", { class: "credits-label" }, "Used"),
createVNode("span", { class: "credits-amount credits-used" }, "$" + toDisplayString(fmt(stats.value.credits.used)), 1)
]),
createVNode("div", { class: "credits-stat" }, [
createVNode("span", { class: "credits-label" }, "Remaining"),
createVNode("span", { class: "credits-amount credits-remaining" }, "$" + toDisplayString(fmt(stats.value.credits.remaining)), 1)
]),
createVNode("div", { class: "credits-stat" }, [
createVNode("span", { class: "credits-label" }, "Total"),
createVNode("span", { class: "credits-amount" }, "$" + toDisplayString(fmt(stats.value.credits.total)), 1)
])
])
])) : createCommentVNode("", true)
]),
stats.value ? (openBlock(), createBlock("div", {
key: 2,
class: "dev-section"
}, [
createVNode("h3", null, "Agents"),
createVNode("div", { class: "dev-table-wrap" }, [
createVNode("table", { class: "dev-table" }, [
createVNode("thead", null, [
createVNode("tr", null, [
createVNode("th", null, "Agent"),
createVNode("th", null, "Model"),
createVNode("th", null, "Context"),
createVNode("th", null, "Prompt / 1M"),
createVNode("th", null, "Completion / 1M")
])
]),
createVNode("tbody", null, [
(openBlock(true), createBlock(Fragment, null, renderList(stats.value.agents, (a) => {
return openBlock(), createBlock("tr", {
key: a.id
}, [
createVNode("td", { class: "agent-id" }, toDisplayString(a.id), 1),
createVNode("td", null, [
createVNode("code", null, toDisplayString(a.modelId || a.model), 1)
]),
createVNode("td", null, toDisplayString(a.contextLength ? (a.contextLength / 1e3).toFixed(0) + "k" : "—"), 1),
createVNode("td", null, toDisplayString(a.promptPrice !== null ? "$" + a.promptPrice.toFixed(3) : "—"), 1),
createVNode("td", null, toDisplayString(a.completionPrice !== null ? "$" + a.completionPrice.toFixed(3) : "—"), 1)
]);
}), 128))
])
])
])
])) : createCommentVNode("", true)
])
]),
(openBlock(), createBlock(Teleport, { to: "body" }, [
unref(breakoutReq) ? (openBlock(), createBlock("div", {
key: 0,
class: "breakout-modal-overlay",
onClick: withModifiers(denyBreakout, ["self"])
}, [
createVNode("div", { class: "breakout-modal" }, [
createVNode("h3", null, "Open Breakout"),
createVNode("p", null, [
createTextVNode("Name: "),
createVNode("strong", null, toDisplayString(unref(breakoutReq).name), 1)
]),
createVNode("p", null, [
createTextVNode("Size: "),
createVNode("strong", null, toDisplayString(unref(breakoutReq).preset), 1)
]),
createVNode("p", { class: "breakout-nonce" }, toDisplayString(unref(breakoutReq).nonce), 1),
createVNode("div", { class: "breakout-modal-actions" }, [
createVNode("button", {
class: "dev-theme-btn",
onClick: denyBreakout
}, "Cancel"),
createVNode("button", {
class: "dev-theme-btn active",
onClick: confirmBreakout
}, "Confirm")
])
])
])) : createCommentVNode("", true)
]))
];
}
}),
_: 1
}, _parent));
} else {
_push(`<div${ssrRenderAttrs(mergeProps({ class: "not-logged-in" }, _attrs))} data-v-6fcff79f><p data-v-6fcff79f>`);
_push(ssrRenderComponent(unref(LockClosedIcon), { class: "w-5 h-5 inline" }, null, _parent));
_push(` Not logged in</p>`);
_push(ssrRenderComponent(_component_RouterLink, { to: "/login" }, {
default: withCtx((_, _push2, _parent2, _scopeId) => {
if (_push2) {
_push2(`Sign in →`);
} else {
return [
createTextVNode("Sign in →")
];
}
}),
_: 1
}, _parent));
_push(`</div>`);
}
};
}
});
const _sfc_setup = _sfc_main.setup;
_sfc_main.setup = (props, ctx) => {
const ssrContext = useSSRContext();
(ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("src/views/DevView.vue");
return _sfc_setup ? _sfc_setup(props, ctx) : void 0;
};
const DevView = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-6fcff79f"]]);
export {
DevView as default
};

View File

@ -1,50 +0,0 @@
import { resolveComponent, mergeProps, withCtx, createTextVNode, useSSRContext } from "vue";
import { ssrRenderAttrs, ssrRenderComponent } from "vue/server-renderer";
import { _ as _export_sfc } from "../main.mjs";
import "@unhead/vue/server";
import "vue-router";
import "pinia";
import "@heroicons/vue/24/outline";
import "@heroicons/vue/20/solid";
import "overlayscrollbars-vue";
import "overlayscrollbars";
const _sfc_main = {};
function _sfc_ssrRender(_ctx, _push, _parent, _attrs) {
const _component_router_link = resolveComponent("router-link");
_push(`<div${ssrRenderAttrs(mergeProps({ class: "legal-page" }, _attrs))} data-v-d8c150db><h1 data-v-d8c150db>Impressum</h1><h2 data-v-d8c150db>Angaben gemäß § 5 TMG</h2><p data-v-d8c150db> loop42 UG (haftungsbeschränkt)<br data-v-d8c150db> [STRASSE HAUSNUMMER]<br data-v-d8c150db> [PLZ ORT]<br data-v-d8c150db> Deutschland </p><h2 data-v-d8c150db>Vertreten durch</h2><p data-v-d8c150db>[NAME]</p><h2 data-v-d8c150db>Kontakt</h2><p data-v-d8c150db>Telefon: [TELEFONNUMMER]</p><h2 data-v-d8c150db>Registereintrag</h2><p data-v-d8c150db> Eintragung im Handelsregister.<br data-v-d8c150db> Registergericht: [AMTSGERICHT]<br data-v-d8c150db> Registernummer: [HRB-NUMMER] </p><h2 data-v-d8c150db>Umsatzsteuer-ID</h2><p data-v-d8c150db> Umsatzsteuer-Identifikationsnummer gemäß § 27 a Umsatzsteuergesetz:<br data-v-d8c150db> [UST-ID-NUMMER] </p><h2 data-v-d8c150db>Verantwortlich für den Inhalt nach § 55 Abs. 2 RStV</h2><p data-v-d8c150db> [NAME]<br data-v-d8c150db> [STRASSE HAUSNUMMER]<br data-v-d8c150db> [PLZ ORT] </p><h2 data-v-d8c150db>Streitschlichtung</h2><p data-v-d8c150db> Die Europäische Kommission stellt eine Plattform zur Online-Streitbeilegung (OS) bereit: <a href="https://ec.europa.eu/consumers/odr/" target="_blank" rel="noopener" data-v-d8c150db>https://ec.europa.eu/consumers/odr/</a>.<br data-v-d8c150db> Unsere E-Mail-Adresse finden Sie oben im Impressum. </p><p data-v-d8c150db> Wir sind nicht bereit oder verpflichtet, an Streitbeilegungsverfahren vor einer Verbraucherschlichtungsstelle teilzunehmen. </p><footer data-v-d8c150db><div class="footer-links" data-v-d8c150db>`);
_push(ssrRenderComponent(_component_router_link, { to: "/impressum" }, {
default: withCtx((_, _push2, _parent2, _scopeId) => {
if (_push2) {
_push2(`Impressum`);
} else {
return [
createTextVNode("Impressum")
];
}
}),
_: 1
}, _parent));
_push(ssrRenderComponent(_component_router_link, { to: "/datenschutz" }, {
default: withCtx((_, _push2, _parent2, _scopeId) => {
if (_push2) {
_push2(`Datenschutz`);
} else {
return [
createTextVNode("Datenschutz")
];
}
}),
_: 1
}, _parent));
_push(`</div><span data-v-d8c150db>© 2026 loop42 UG (haftungsbeschränkt)</span></footer></div>`);
}
const _sfc_setup = _sfc_main.setup;
_sfc_main.setup = (props, ctx) => {
const ssrContext = useSSRContext();
(ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("src/views/ImpressumView.vue");
return _sfc_setup ? _sfc_setup(props, ctx) : void 0;
};
const ImpressumView = /* @__PURE__ */ _export_sfc(_sfc_main, [["ssrRender", _sfc_ssrRender], ["__scopeId", "data-v-d8c150db"]]);
export {
ImpressumView as default
};

View File

@ -1,445 +0,0 @@
import { computed, ref, onMounted, watch, onUnmounted, defineComponent, mergeProps, unref, withCtx, openBlock, createBlock, createVNode, toDisplayString, Fragment, renderList, createCommentVNode, createTextVNode, useSSRContext } from "vue";
import { ssrRenderAttrs, ssrRenderList, ssrRenderClass, ssrInterpolate, ssrRenderAttr, ssrRenderComponent } from "vue/server-renderer";
import { OverlayScrollbarsComponent } from "overlayscrollbars-vue";
import { i as useViewerStore, g as getApiBase, w as ws, l as lastViewerPath, s as scrollbarOptions, _ as _export_sfc } from "../main.mjs";
import { ArrowDownTrayIcon, FolderOpenIcon, FolderIcon, DocumentIcon } from "@heroicons/vue/20/solid";
import { useRoute, useRouter } from "vue-router";
import { marked } from "marked";
import "@unhead/vue/server";
import "pinia";
import "@heroicons/vue/24/outline";
import "overlayscrollbars";
function useViewer() {
const route = useRoute();
const router = useRouter();
const { onMessage } = ws;
const viewerStore = useViewerStore();
const fstoken = computed(() => viewerStore.fstoken);
const viewerRoots = computed(() => viewerStore.roots);
const token = fstoken;
function normalizePath(path) {
if (!path) return path;
const roots = viewerStore.roots;
if (!roots.length) return path;
const [prefix, ...rest] = path.split("/");
if (roots.includes(prefix)) return path;
const canonical = roots.find((r) => r === `workspace-${prefix}` || r.endsWith(`-${prefix}`));
return canonical ? [canonical, ...rest].join("/") : path;
}
const currentPath = ref(normalizePath(
route.query.path || localStorage.getItem("viewer_last_path") || ""
));
const sidebarCollapsed = ref(window.innerWidth < 768);
const content = ref("");
const fileType = ref("");
const dirFiles = ref([]);
const dirDirs = ref([]);
const loading = ref(false);
const showLoading = ref(false);
let loadingTimer = null;
const fetchError = ref("");
const pdfCacheBust = ref(Date.now());
const mdRaw = ref(false);
const mdLineCount = computed(() => {
if (!content.value) return 0;
return content.value.split("\n").length;
});
const renderedMd = computed(() => {
if (fileType.value !== "md" || !content.value) return "";
return marked.parse(content.value);
});
const pdfSrc = computed(() => {
if (fileType.value !== "pdf" || !currentPath.value || !token.value) return "";
const base = getBaseUrl();
return `${base}/api/viewer/file?path=${encodeURIComponent(currentPath.value)}&token=${encodeURIComponent(token.value)}&t=${pdfCacheBust.value}`;
});
function getBaseUrl() {
return getApiBase();
}
function extOf(p) {
const m = p.match(/\.([^./]+)$/);
return m ? m[1].toLowerCase() : "";
}
function startLoading(silent) {
if (silent) return;
loading.value = true;
showLoading.value = false;
if (loadingTimer) clearTimeout(loadingTimer);
loadingTimer = setTimeout(() => {
showLoading.value = true;
}, 3e3);
}
function stopLoading() {
loading.value = false;
showLoading.value = false;
if (loadingTimer) {
clearTimeout(loadingTimer);
loadingTimer = null;
}
}
async function fetchContent(path, silent = false, _retry = false) {
startLoading(silent);
try {
const base = getBaseUrl();
const url = `${base}/api/viewer/file?path=${encodeURIComponent(path)}&token=${encodeURIComponent(token.value)}`;
const res = await fetch(url);
if (res.status === 401 && !_retry) {
viewerStore.invalidate();
await viewerStore.acquire(true);
return fetchContent(path, silent, true);
}
if (!res.ok) {
fetchError.value = `${res.status}: ${await res.text()}`;
return;
}
fetchError.value = "";
content.value = await res.text();
} catch (e) {
fetchError.value = e.message || "Fetch failed";
} finally {
stopLoading();
}
}
async function openFile(path) {
path = normalizePath(path);
currentPath.value = path;
localStorage.setItem("viewer_last_path", path);
lastViewerPath.value = path;
if (route.query.path !== path) {
router.push({ name: "viewer", query: { path } });
}
const ext = extOf(path);
if (!path) {
fileType.value = "dir";
content.value = "";
fetchError.value = "";
dirDirs.value = viewerRoots.value.length ? viewerRoots.value : ["shared", "workspace-titan"];
dirFiles.value = [];
return;
}
if (!ext) {
fileType.value = "dir";
content.value = "";
fetchError.value = "";
startLoading(false);
try {
const base = getBaseUrl();
const url = `${base}/api/viewer/tree?root=${encodeURIComponent(path)}&token=${encodeURIComponent(token.value)}`;
const res = await fetch(url);
if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
const data = await res.json();
dirDirs.value = data.dirs || [];
dirFiles.value = data.files || [];
} catch (e) {
dirDirs.value = [];
dirFiles.value = [];
fetchError.value = e.message || "Failed to load directory";
} finally {
stopLoading();
}
return;
}
if (ext === "pdf") {
fileType.value = "pdf";
content.value = "";
fetchError.value = "";
pdfCacheBust.value = Date.now();
fetch(`${getBaseUrl()}/api/viewer/file?path=${encodeURIComponent(path)}&token=${encodeURIComponent(token.value)}`, { method: "HEAD" }).catch(() => {
});
return;
}
fileType.value = ext === "md" ? "md" : "text";
fetchError.value = "";
await fetchContent(path, false);
}
function onCopy(e) {
const sel = window.getSelection();
if (!sel || sel.isCollapsed) return;
const html = (() => {
const div = document.createElement("div");
div.appendChild(sel.getRangeAt(0).cloneContents());
return div.innerHTML;
})();
const clean = html.replace(/background(-color)?:[^;"]*(;|(?="))/gi, "");
const plain = sel.toString();
e.clipboardData.setData("text/html", clean);
e.clipboardData.setData("text/plain", plain);
e.preventDefault();
}
async function refreshFile(path) {
const ext = extOf(path);
if (ext === "pdf") {
pdfCacheBust.value = Date.now();
return;
}
await fetchContent(path, true);
}
let unsubscribe = null;
onMounted(() => {
unsubscribe = onMessage((data) => {
if (data.type === "viewer_file_changed" && data.path === currentPath.value) {
refreshFile(currentPath.value);
}
if (data.type === "viewer_tree_changed" && data.path === currentPath.value && fileType.value === "dir") {
openFile(currentPath.value);
}
});
viewerStore.acquire();
if (currentPath.value) openFile(currentPath.value);
});
watch(() => route.query.path, (newPath) => {
if (newPath && newPath !== currentPath.value) {
openFile(newPath);
}
});
onUnmounted(() => {
if (unsubscribe) unsubscribe();
});
return {
fstoken,
viewerRoots,
currentPath,
sidebarCollapsed,
content,
fileType,
loading,
fetchError,
mdRaw,
mdLineCount,
renderedMd,
pdfSrc,
openFile,
onCopy,
dirFiles,
dirDirs,
showLoading
};
}
const _sfc_main = /* @__PURE__ */ defineComponent({
...{ name: "ViewerView" },
__name: "ViewerView",
__ssrInlineRender: true,
setup(__props) {
const {
fstoken,
currentPath,
content,
fileType,
showLoading,
fetchError,
mdRaw,
renderedMd,
pdfSrc,
openFile,
onCopy,
dirFiles,
dirDirs
} = useViewer();
const contentLines = computed(() => content.value.split("\n"));
const fileName = computed(() => {
if (!currentPath.value) return "";
return currentPath.value.split("/").pop() || "";
});
const downloadUrl = computed(() => {
if (!currentPath.value || !fstoken.value) return "";
return `${getApiBase()}/api/viewer/file?path=${encodeURIComponent(currentPath.value)}&token=${encodeURIComponent(fstoken.value)}&dl=1`;
});
const breadcrumbs = computed(() => {
const crumbs = [{ label: "files", path: "" }];
if (!currentPath.value) return crumbs;
const parts = currentPath.value.split("/");
for (let i = 0; i < parts.length; i++) {
crumbs.push({ label: parts[i], path: parts.slice(0, i + 1).join("/") });
}
return crumbs;
});
return (_ctx, _push, _parent, _attrs) => {
_push(`<div${ssrRenderAttrs(mergeProps({ class: "viewer-layout h-full overflow-hidden" }, _attrs))} data-v-6b5cb038><main class="viewer-pane min-w-0 flex flex-col h-full overflow-hidden" data-v-6b5cb038>`);
if (unref(currentPath) || unref(fileType) === "dir") {
_push(`<div class="viewer-toolbar" data-v-6b5cb038><div class="viewer-panel breadcrumb-panel" data-v-6b5cb038><!--[-->`);
ssrRenderList(breadcrumbs.value, (crumb, i) => {
_push(`<span data-v-6b5cb038>`);
if (i > 0) {
_push(`<span class="breadcrumb-sep" data-v-6b5cb038>/</span>`);
} else {
_push(`<!---->`);
}
_push(`<span class="${ssrRenderClass([{ active: i === breadcrumbs.value.length - 1 }, "breadcrumb-item"])}" data-v-6b5cb038>${ssrInterpolate(crumb.label)}</span></span>`);
});
_push(`<!--]--></div><div class="viewer-toolbar-spacer" data-v-6b5cb038></div>`);
if (unref(fileType) === "md") {
_push(`<div class="viewer-panel toggle-panel" data-v-6b5cb038><button class="${ssrRenderClass([{ active: !unref(mdRaw) }, "md-toggle-btn"])}" data-v-6b5cb038>Rendered</button><button class="${ssrRenderClass([{ active: unref(mdRaw) }, "md-toggle-btn"])}" data-v-6b5cb038>Raw</button></div>`);
} else {
_push(`<!---->`);
}
if (unref(fileType) && unref(fileType) !== "dir") {
_push(`<a class="viewer-panel download-panel"${ssrRenderAttr("href", downloadUrl.value)}${ssrRenderAttr("download", fileName.value)} title="Download" data-v-6b5cb038>`);
_push(ssrRenderComponent(unref(ArrowDownTrayIcon), { class: "w-4 h-4" }, null, _parent));
_push(`</a>`);
} else {
_push(`<!---->`);
}
_push(`</div>`);
} else {
_push(`<!---->`);
}
_push(ssrRenderComponent(unref(OverlayScrollbarsComponent), {
class: "content flex-1 min-h-0",
options: unref(scrollbarOptions),
element: "div"
}, {
default: withCtx((_, _push2, _parent2, _scopeId) => {
if (_push2) {
if (!unref(currentPath) && unref(fileType) !== "dir") {
_push2(`<div class="viewer-empty" data-v-6b5cb038${_scopeId}>`);
_push2(ssrRenderComponent(unref(FolderOpenIcon), { class: "w-8 h-8 text-text-dim" }, null, _parent2, _scopeId));
_push2(`<p data-v-6b5cb038${_scopeId}>Select a file from the tree</p></div>`);
} else if (unref(showLoading)) {
_push2(`<div class="viewer-loading" data-v-6b5cb038${_scopeId}>loading…</div>`);
} else if (unref(fetchError)) {
_push2(`<div class="viewer-error" data-v-6b5cb038${_scopeId}>${ssrInterpolate(unref(fetchError))}</div>`);
} else if (unref(fileType) === "dir") {
_push2(`<div class="viewer-dir" data-v-6b5cb038${_scopeId}><!--[-->`);
ssrRenderList(unref(dirDirs), (d) => {
_push2(`<div class="dir-entry dir-entry--dir" data-v-6b5cb038${_scopeId}>`);
_push2(ssrRenderComponent(unref(FolderIcon), { class: "w-4 h-4" }, null, _parent2, _scopeId));
_push2(`<span data-v-6b5cb038${_scopeId}>${ssrInterpolate(d)}/</span></div>`);
});
_push2(`<!--]--><!--[-->`);
ssrRenderList(unref(dirFiles), (f) => {
_push2(`<div class="dir-entry dir-entry--file" data-v-6b5cb038${_scopeId}>`);
_push2(ssrRenderComponent(unref(DocumentIcon), { class: "w-4 h-4" }, null, _parent2, _scopeId));
_push2(`<span data-v-6b5cb038${_scopeId}>${ssrInterpolate(f.name)}</span></div>`);
});
_push2(`<!--]-->`);
if (!unref(dirDirs).length && !unref(dirFiles).length) {
_push2(`<div class="viewer-empty" data-v-6b5cb038${_scopeId}><p data-v-6b5cb038${_scopeId}>Empty directory</p></div>`);
} else {
_push2(`<!---->`);
}
_push2(`</div>`);
} else if (unref(fileType) === "pdf") {
_push2(`<iframe class="viewer-pdf"${ssrRenderAttr("src", unref(pdfSrc))} frameborder="0" data-v-6b5cb038${_scopeId}></iframe>`);
} else if (unref(fileType) === "md" && !unref(mdRaw)) {
_push2(`<div class="viewer-md md-body" data-v-6b5cb038${_scopeId}>${unref(renderedMd) ?? ""}</div>`);
} else if (unref(fileType) === "md" && unref(mdRaw)) {
_push2(`<div class="viewer-raw-md" data-v-6b5cb038${_scopeId}><pre class="viewer-raw-code" data-v-6b5cb038${_scopeId}><code data-v-6b5cb038${_scopeId}><!--[-->`);
ssrRenderList(contentLines.value, (line, i) => {
_push2(`<span class="code-line" data-v-6b5cb038${_scopeId}><span class="line-num" data-v-6b5cb038${_scopeId}>${ssrInterpolate(i + 1)}</span>${ssrInterpolate(line)}
</span>`);
});
_push2(`<!--]--></code></pre></div>`);
} else {
_push2(`<pre class="viewer-raw-code" data-v-6b5cb038${_scopeId}><code data-v-6b5cb038${_scopeId}><!--[-->`);
ssrRenderList(contentLines.value, (line, i) => {
_push2(`<span class="code-line" data-v-6b5cb038${_scopeId}><span class="line-num" data-v-6b5cb038${_scopeId}>${ssrInterpolate(i + 1)}</span>${ssrInterpolate(line)}
</span>`);
});
_push2(`<!--]--></code></pre>`);
}
} else {
return [
!unref(currentPath) && unref(fileType) !== "dir" ? (openBlock(), createBlock("div", {
key: 0,
class: "viewer-empty"
}, [
createVNode(unref(FolderOpenIcon), { class: "w-8 h-8 text-text-dim" }),
createVNode("p", null, "Select a file from the tree")
])) : unref(showLoading) ? (openBlock(), createBlock("div", {
key: 1,
class: "viewer-loading"
}, "loading…")) : unref(fetchError) ? (openBlock(), createBlock("div", {
key: 2,
class: "viewer-error"
}, toDisplayString(unref(fetchError)), 1)) : unref(fileType) === "dir" ? (openBlock(), createBlock("div", {
key: 3,
class: "viewer-dir"
}, [
(openBlock(true), createBlock(Fragment, null, renderList(unref(dirDirs), (d) => {
return openBlock(), createBlock("div", {
key: d,
class: "dir-entry dir-entry--dir",
onClick: ($event) => unref(openFile)(unref(currentPath) ? unref(currentPath) + "/" + d : d)
}, [
createVNode(unref(FolderIcon), { class: "w-4 h-4" }),
createVNode("span", null, toDisplayString(d) + "/", 1)
], 8, ["onClick"]);
}), 128)),
(openBlock(true), createBlock(Fragment, null, renderList(unref(dirFiles), (f) => {
return openBlock(), createBlock("div", {
key: f.path,
class: "dir-entry dir-entry--file",
onClick: ($event) => unref(openFile)(f.path)
}, [
createVNode(unref(DocumentIcon), { class: "w-4 h-4" }),
createVNode("span", null, toDisplayString(f.name), 1)
], 8, ["onClick"]);
}), 128)),
!unref(dirDirs).length && !unref(dirFiles).length ? (openBlock(), createBlock("div", {
key: 0,
class: "viewer-empty"
}, [
createVNode("p", null, "Empty directory")
])) : createCommentVNode("", true)
])) : unref(fileType) === "pdf" ? (openBlock(), createBlock("iframe", {
key: 4,
class: "viewer-pdf",
src: unref(pdfSrc),
frameborder: "0"
}, null, 8, ["src"])) : unref(fileType) === "md" && !unref(mdRaw) ? (openBlock(), createBlock("div", {
key: 5,
class: "viewer-md md-body",
innerHTML: unref(renderedMd),
onCopy: unref(onCopy)
}, null, 40, ["innerHTML", "onCopy"])) : unref(fileType) === "md" && unref(mdRaw) ? (openBlock(), createBlock("div", {
key: 6,
class: "viewer-raw-md"
}, [
createVNode("pre", { class: "viewer-raw-code" }, [
createVNode("code", null, [
(openBlock(true), createBlock(Fragment, null, renderList(contentLines.value, (line, i) => {
return openBlock(), createBlock("span", {
key: i,
class: "code-line"
}, [
createVNode("span", { class: "line-num" }, toDisplayString(i + 1), 1),
createTextVNode(toDisplayString(line) + "\n", 1)
]);
}), 128))
])
])
])) : (openBlock(), createBlock("pre", {
key: 7,
class: "viewer-raw-code"
}, [
createVNode("code", null, [
(openBlock(true), createBlock(Fragment, null, renderList(contentLines.value, (line, i) => {
return openBlock(), createBlock("span", {
key: i,
class: "code-line"
}, [
createVNode("span", { class: "line-num" }, toDisplayString(i + 1), 1),
createTextVNode(toDisplayString(line) + "\n", 1)
]);
}), 128))
])
]))
];
}
}),
_: 1
}, _parent));
_push(`</main></div>`);
};
}
});
const _sfc_setup = _sfc_main.setup;
_sfc_main.setup = (props, ctx) => {
const ssrContext = useSSRContext();
(ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("src/views/ViewerView.vue");
return _sfc_setup ? _sfc_setup(props, ctx) : void 0;
};
const ViewerView = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-6b5cb038"]]);
export {
ViewerView as default
};

View File

@ -1,11 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<!-- Sun circle -->
<circle cx="16" cy="16" r="10" fill="none" stroke="#005e83" stroke-width="2"/>
<!-- Sun rays -->
<line x1="16" y1="2" x2="16" y2="6" stroke="#e25303" stroke-width="2" stroke-linecap="round"/>
<line x1="16" y1="26" x2="16" y2="30" stroke="#e25303" stroke-width="2" stroke-linecap="round"/>
<line x1="2" y1="16" x2="6" y2="16" stroke="#e25303" stroke-width="2" stroke-linecap="round"/>
<line x1="26" y1="16" x2="30" y2="16" stroke="#e25303" stroke-width="2" stroke-linecap="round"/>
<!-- Inner dot -->
<circle cx="16" cy="16" r="4" fill="#005e83"/>
</svg>

Before

Width:  |  Height:  |  Size: 653 B

View File

@ -1,9 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<!-- Rounded square background -->
<rect x="2" y="2" width="28" height="28" rx="6" fill="#1A212C" stroke="#1D7872" stroke-width="1.5"/>
<!-- Loop symbol: two interlinked arcs -->
<path d="M10,16 a5,5 0 1,1 6,0 a5,5 0 1,1 -6,0" fill="none" stroke="#71B095" stroke-width="2"/>
<path d="M16,16 a5,5 0 1,1 6,0 a5,5 0 1,1 -6,0" fill="none" stroke="#1D7872" stroke-width="2"/>
<!-- 42 text -->
<text x="16" y="27" font-family="monospace" font-size="6" font-weight="bold" fill="#71B095" text-anchor="middle">42</text>
</svg>

Before

Width:  |  Height:  |  Size: 593 B

View File

@ -1,12 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<!-- Monitor body -->
<rect x="2" y="4" width="28" height="18" rx="2.5" ry="2.5" fill="#1a1a2e" stroke="#7c6ff7" stroke-width="1.5"/>
<!-- Screen inner -->
<rect x="4.5" y="6.5" width="23" height="13" rx="1" fill="#0d0d1a"/>
<!-- Stand neck -->
<rect x="14" y="22" width="4" height="4" fill="#7c6ff7"/>
<!-- Stand base -->
<rect x="10" y="26" width="12" height="2.5" rx="1.2" fill="#7c6ff7"/>
<!-- Lightning bolt on screen -->
<polygon points="18,9 14,16 16.5,16 14,23 20,15 17,15" fill="#f0c040"/>
</svg>

Before

Width:  |  Height:  |  Size: 587 B

View File

@ -1,12 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<!-- Monitor body -->
<rect x="2" y="4" width="28" height="18" rx="2.5" ry="2.5" fill="#1a1a2e" stroke="#7c6ff7" stroke-width="1.5"/>
<!-- Screen inner -->
<rect x="4.5" y="6.5" width="23" height="13" rx="1" fill="#0d0d1a"/>
<!-- Stand neck -->
<rect x="14" y="22" width="4" height="4" fill="#7c6ff7"/>
<!-- Stand base -->
<rect x="10" y="26" width="12" height="2.5" rx="1.2" fill="#7c6ff7"/>
<!-- Lightning bolt on screen -->
<polygon points="18,9 14,16 16.5,16 14,23 20,15 17,15" fill="#f0c040"/>
</svg>

Before

Width:  |  Height:  |  Size: 587 B

File diff suppressed because it is too large Load Diff