mirror of
https://github.com/TencentCloud/Octop.git
synced 2026-10-02 07:34:38 +08:00
* docs: refresh README roadmap, anchors, and product sync (#1211) Align EN/CN README with shipped features and current install/channel docs; fix GitHub heading anchors and drop obsolete extras examples. Co-authored-by: jubaoliang <jubaoliang@tencent.com> Co-authored-by: Cursor <cursoragent@cursor.com> * fix(dashboard): define missing --fn-bg-container theme variable (#1216) Dark-theme surfaces that use var(--fn-bg-container, #fff) — most visibly the knowledge-base Markdown preview body, toolbar and outline panel — resolved to a white background while text stayed light, leaving preview content invisible. Define the variable as #ffffff (light) and #141414 (dark), and point the Admin/Users badge tints that borrowed the name for a translucent fill at --fn-bg-tertiary so their look is unchanged. Fixes #1215 * feat(dashboard): let each account customize the sidebar (#1218) Store group order, item placement, and hidden entries on the user so navigation can be rearranged without showing items the account cannot access. Co-authored-by: jubaoliang <jubaoliang@tencent.com> Co-authored-by: Cursor <cursoragent@cursor.com> * style(dashboard): apply Prettier to files that drifted from the formatter (#1222) Co-authored-by: jubaoliang <jubaoliang@tencent.com> Co-authored-by: Cursor <cursoragent@cursor.com> * feat: store role-template id on users.role and harden mobile composer (#1220) Collapse the dual user_role_id / role model so users.role and invites.role hold the template public id, block deleting roles still in use, and keep the chat composer visible under mobile browser visualViewport. Co-authored-by: jubaoliang <jubaoliang@tencent.com> Co-authored-by: Cursor <cursoragent@cursor.com> * docs: use product names for sibling project links in the README (#1225) Link labels now match the product names while the repository URLs stay unchanged. Co-authored-by: jubaoliang <jubaoliang@tencent.com> Co-authored-by: Cursor <cursoragent@cursor.com> * chore: release 1.0.2b4 Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: jubaoliang <jubaoliang@tencent.com> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Dang Zitou <dengzitao888@163.com>
315 lines
9.6 KiB
HTML
315 lines
9.6 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<link rel="icon" type="image/svg+xml" href="/favico.svg" />
|
|
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
|
|
<meta
|
|
name="viewport"
|
|
content="width=device-width, initial-scale=1.0, viewport-fit=cover, interactive-widget=resizes-content"
|
|
/>
|
|
<!-- PWA: theme color (light / dark) -->
|
|
<meta
|
|
name="theme-color"
|
|
content="#ffffff"
|
|
media="(prefers-color-scheme: light)"
|
|
/>
|
|
<meta
|
|
name="theme-color"
|
|
content="#1a1c28"
|
|
media="(prefers-color-scheme: dark)"
|
|
/>
|
|
<!-- PWA: standalone mode for iOS Safari -->
|
|
<meta name="mobile-web-app-capable" content="yes" />
|
|
<meta name="apple-mobile-web-app-capable" content="yes" />
|
|
<meta
|
|
name="apple-mobile-web-app-status-bar-style"
|
|
content="black-translucent"
|
|
/>
|
|
<meta name="apple-mobile-web-app-title" content="Octop" />
|
|
<!-- Web App Manifest -->
|
|
<link rel="manifest" href="/manifest.json" />
|
|
<title>Octop</title>
|
|
<!--
|
|
Resolve dashboard theme before first paint. Must stay a classic script:
|
|
the splash CSS keys off html[data-theme], not prefers-color-scheme,
|
|
so a stored "light" preference wins over an OS dark setting.
|
|
Storage shape matches appearanceStorage.ts (THEME_STORAGE_KEY = "theme").
|
|
-->
|
|
<script id="octop-boot-theme">
|
|
(function () {
|
|
var KEY = "theme";
|
|
var mode = "light";
|
|
function systemDark() {
|
|
try {
|
|
return window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
}
|
|
try {
|
|
var raw = localStorage.getItem(KEY);
|
|
var pref = "system";
|
|
if (raw === "light" || raw === "dark" || raw === "system") {
|
|
pref = raw;
|
|
} else if (raw) {
|
|
var parsed = JSON.parse(raw);
|
|
if (
|
|
parsed &&
|
|
(parsed.preference === "light" ||
|
|
parsed.preference === "dark" ||
|
|
parsed.preference === "system")
|
|
) {
|
|
pref = parsed.preference;
|
|
}
|
|
}
|
|
if (pref === "dark" || (pref === "system" && systemDark())) {
|
|
mode = "dark";
|
|
}
|
|
} catch (e) {
|
|
if (systemDark()) mode = "dark";
|
|
}
|
|
document.documentElement.setAttribute("data-theme", mode);
|
|
var themeColor = mode === "dark" ? "#1a1c28" : "#ffffff";
|
|
var metas = document.querySelectorAll('meta[name="theme-color"]');
|
|
for (var i = 0; i < metas.length; i++) {
|
|
metas[i].setAttribute("content", themeColor);
|
|
metas[i].removeAttribute("media");
|
|
}
|
|
})();
|
|
</script>
|
|
<!--
|
|
First-paint boot splash: visible before JS chunks parse. React.createRoot
|
|
replaces #root contents on mount, so this disappears automatically.
|
|
-->
|
|
<style>
|
|
html,
|
|
body {
|
|
height: 100%;
|
|
margin: 0;
|
|
background: #f7f8fa;
|
|
}
|
|
#root {
|
|
min-height: 100%;
|
|
min-height: 100lvh;
|
|
}
|
|
#octop-boot {
|
|
/* fixed + inset: always viewport-centered before app CSS sets #root height */
|
|
position: fixed;
|
|
inset: 0;
|
|
z-index: 2147483646;
|
|
box-sizing: border-box;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 20px;
|
|
padding: max(24px, env(safe-area-inset-top, 0px))
|
|
max(24px, env(safe-area-inset-right, 0px))
|
|
max(24px, env(safe-area-inset-bottom, 0px))
|
|
max(24px, env(safe-area-inset-left, 0px));
|
|
margin: 0;
|
|
background: #f7f8fa;
|
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI",
|
|
"Noto Sans SC", sans-serif;
|
|
color: #8b8fa3;
|
|
}
|
|
html[data-theme="dark"],
|
|
html[data-theme="dark"] body {
|
|
background: #12141c;
|
|
}
|
|
html[data-theme="dark"] #octop-boot {
|
|
background: #12141c;
|
|
color: rgba(255, 255, 255, 0.55);
|
|
}
|
|
#octop-boot-mark {
|
|
position: relative;
|
|
width: 88px;
|
|
height: 88px;
|
|
flex: none;
|
|
}
|
|
#octop-boot-ring {
|
|
box-sizing: border-box;
|
|
position: absolute;
|
|
inset: 0;
|
|
border-radius: 50%;
|
|
border: 3px solid rgba(232, 93, 117, 0.18);
|
|
border-top-color: #e85d75;
|
|
animation: octop-boot-spin 0.85s linear infinite;
|
|
}
|
|
html[data-theme="dark"] #octop-boot-ring {
|
|
border-color: rgba(240, 139, 154, 0.22);
|
|
border-top-color: #f08b9a;
|
|
}
|
|
.octop-boot-logo {
|
|
position: absolute;
|
|
inset: 14px;
|
|
width: 60px;
|
|
height: 60px;
|
|
border-radius: 14px;
|
|
object-fit: contain;
|
|
display: block;
|
|
animation: octop-boot-breathe 1.6s ease-in-out infinite;
|
|
}
|
|
.octop-boot-logo--dark {
|
|
display: none;
|
|
}
|
|
html[data-theme="dark"] .octop-boot-logo--light {
|
|
display: none;
|
|
}
|
|
html[data-theme="dark"] .octop-boot-logo--dark {
|
|
display: block;
|
|
}
|
|
#octop-boot-text {
|
|
font-size: 14px;
|
|
font-weight: 500;
|
|
letter-spacing: 0.04em;
|
|
user-select: none;
|
|
}
|
|
@keyframes octop-boot-spin {
|
|
to {
|
|
transform: rotate(360deg);
|
|
}
|
|
}
|
|
@keyframes octop-boot-breathe {
|
|
0%,
|
|
100% {
|
|
transform: scale(1);
|
|
opacity: 1;
|
|
}
|
|
50% {
|
|
transform: scale(0.94);
|
|
opacity: 0.88;
|
|
}
|
|
}
|
|
@media (prefers-reduced-motion: reduce) {
|
|
#octop-boot-ring,
|
|
.octop-boot-logo {
|
|
animation: none;
|
|
}
|
|
}
|
|
</style>
|
|
<!--
|
|
Classic script (not type=module) so it runs even when hashed chunks 404.
|
|
Shares octop:chunk-reload with reloadOnStaleChunk.ts.
|
|
-->
|
|
<script>
|
|
(function () {
|
|
// Chromium 91 and earlier do not provide this ES2022 API, while some
|
|
// dashboard dependencies call it. Run before any ESM chunks evaluate.
|
|
if (typeof Object.hasOwn !== "function") {
|
|
Object.defineProperty(Object, "hasOwn", {
|
|
value: function hasOwn(object, property) {
|
|
return Object.prototype.hasOwnProperty.call(object, property);
|
|
},
|
|
configurable: true,
|
|
writable: true,
|
|
});
|
|
}
|
|
|
|
var KEY = "octop:chunk-reload";
|
|
// Firefox fires error on <link rel="modulepreload"> for /assets/*.js
|
|
// even when the file is fine; treating those as stale chunks caused
|
|
// infinite location.reload() loops (and aborted real dynamic imports).
|
|
var recovering = false;
|
|
function isAsset(url) {
|
|
return typeof url === "string" && url.indexOf("/assets/") !== -1;
|
|
}
|
|
function isStylesheetLink(el) {
|
|
if (!el || el.tagName !== "LINK") return false;
|
|
var rel = (el.rel || "").toLowerCase();
|
|
return rel.indexOf("stylesheet") !== -1;
|
|
}
|
|
function recover() {
|
|
if (recovering) return;
|
|
try {
|
|
if (sessionStorage.getItem(KEY) === "1") {
|
|
sessionStorage.removeItem(KEY);
|
|
return;
|
|
}
|
|
sessionStorage.setItem(KEY, "1");
|
|
} catch (e) {}
|
|
recovering = true;
|
|
var reload = function () {
|
|
location.reload();
|
|
};
|
|
var bust = Promise.resolve();
|
|
if ("serviceWorker" in navigator) {
|
|
bust = navigator.serviceWorker
|
|
.getRegistrations()
|
|
.then(function (regs) {
|
|
return Promise.all(
|
|
regs.map(function (r) {
|
|
return r.unregister();
|
|
}),
|
|
);
|
|
});
|
|
}
|
|
if ("caches" in window) {
|
|
bust = bust.then(function () {
|
|
return caches.keys().then(function (keys) {
|
|
return Promise.all(
|
|
keys.map(function (k) {
|
|
return caches.delete(k);
|
|
}),
|
|
);
|
|
});
|
|
});
|
|
}
|
|
bust.then(reload, reload);
|
|
}
|
|
window.addEventListener(
|
|
"error",
|
|
function (e) {
|
|
var t = e.target;
|
|
if (!t || !t.tagName) return;
|
|
if (t.tagName === "SCRIPT" && isAsset(t.src)) recover();
|
|
// Only stylesheets — never modulepreload / preload (Firefox noise).
|
|
if (isStylesheetLink(t) && isAsset(t.href)) recover();
|
|
},
|
|
true,
|
|
);
|
|
})();
|
|
</script>
|
|
</head>
|
|
<body>
|
|
<div id="root">
|
|
<div id="octop-boot" role="status" aria-live="polite">
|
|
<div id="octop-boot-mark" aria-hidden="true">
|
|
<div id="octop-boot-ring"></div>
|
|
<img
|
|
class="octop-boot-logo octop-boot-logo--light"
|
|
src="/logo_vertical_dark.svg"
|
|
alt=""
|
|
width="60"
|
|
height="60"
|
|
/>
|
|
<img
|
|
class="octop-boot-logo octop-boot-logo--dark"
|
|
src="/logo_vertical_white.svg"
|
|
alt=""
|
|
width="60"
|
|
height="60"
|
|
/>
|
|
</div>
|
|
<div id="octop-boot-text">Loading…</div>
|
|
</div>
|
|
</div>
|
|
<script>
|
|
(function () {
|
|
var el = document.getElementById("octop-boot-text");
|
|
if (!el) return;
|
|
try {
|
|
var lang = (
|
|
navigator.language ||
|
|
navigator.userLanguage ||
|
|
""
|
|
).toLowerCase();
|
|
if (lang.indexOf("zh") === 0) el.textContent = "加载中…";
|
|
} catch (e) {}
|
|
})();
|
|
</script>
|
|
<script type="module" src="/src/main.tsx"></script>
|
|
</body>
|
|
</html>
|