diff --git a/web/storyforge-web-v4/assets/app.js b/web/storyforge-web-v4/assets/app.js
index 4ea6ed0..629f3e9 100644
--- a/web/storyforge-web-v4/assets/app.js
+++ b/web/storyforge-web-v4/assets/app.js
@@ -169,34 +169,36 @@ function ensureAuthUi() {
modal.className = "auth-modal-backdrop hidden";
modal.innerHTML = `
-
-
-
连接 StoryForge
-
先登录后端,再加载项目、对标、Agent 和生产数据。
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
`;
document.body.appendChild(modal);
@@ -2442,17 +2444,8 @@ document.addEventListener("click", async (event) => {
return;
}
if (name === "submit-auth") {
- setBusy(true, "正在登录并加载...");
- try {
- await loginWithForm();
- closeAuthModal();
- await bootstrap();
- } catch (error) {
- const message = document.querySelector('[data-role="auth-message"]');
- if (message) message.textContent = error.message;
- } finally {
- setBusy(false, "");
- }
+ // Auth form submission is handled centrally so clicking the submit
+ // button and pressing Enter share the same code path.
return;
}
if (name === "auth-refresh" || name === "refresh-data") {
@@ -2610,6 +2603,23 @@ document.addEventListener("input", (event) => {
}
});
+document.addEventListener("submit", async (event) => {
+ const form = event.target;
+ if (!(form instanceof HTMLFormElement) || form.dataset.role !== "auth-form") return;
+ event.preventDefault();
+ setBusy(true, "正在登录并加载...");
+ try {
+ await loginWithForm();
+ closeAuthModal();
+ await bootstrap();
+ } catch (error) {
+ const message = document.querySelector('[data-role="auth-message"]');
+ if (message) message.textContent = error.message;
+ } finally {
+ setBusy(false, "");
+ }
+});
+
navButtons.forEach((button) => {
button.addEventListener("click", () => {
const next = button.dataset.screenTarget;
diff --git a/web/storyforge-web-v4/assets/styles.css b/web/storyforge-web-v4/assets/styles.css
index cb04a3f..941f978 100644
--- a/web/storyforge-web-v4/assets/styles.css
+++ b/web/storyforge-web-v4/assets/styles.css
@@ -213,6 +213,16 @@ select {
min-width: 0;
}
+.topbar-left {
+ flex: 1 1 auto;
+}
+
+.topbar-right {
+ flex: 1 1 auto;
+ justify-content: flex-end;
+ flex-wrap: wrap;
+}
+
.workspace-switch,
.search,
.mini-card {
@@ -234,6 +244,8 @@ select {
.workspace-switch span {
font-size: 12px;
color: var(--muted);
+ display: block;
+ line-height: 1.4;
}
.search {
@@ -279,6 +291,7 @@ select {
display: flex;
align-items: center;
gap: 10px;
+ flex-wrap: wrap;
}
.auth-status {
@@ -314,6 +327,11 @@ select {
padding: 22px;
}
+.auth-form {
+ display: grid;
+ gap: 0;
+}
+
.action-modal-backdrop {
position: fixed;
inset: 0;
@@ -1144,18 +1162,37 @@ tbody tr:hover {
border-radius: 18px;
}
+ .topbar-left .chip-row,
+ .topbar-right {
+ width: 100%;
+ }
+
+ .topbar-left .chip-row {
+ flex-wrap: nowrap;
+ overflow-x: auto;
+ padding-bottom: 2px;
+ scrollbar-width: none;
+ }
+
+ .topbar-left .chip-row::-webkit-scrollbar {
+ display: none;
+ }
+
.top-pill {
padding: 7px 10px;
}
.auth-inline {
- flex-wrap: wrap;
width: 100%;
+ display: grid;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ gap: 8px;
}
.auth-status {
max-width: none;
width: 100%;
+ grid-column: 1 / -1;
}
.auth-modal-backdrop,
@@ -1332,6 +1369,7 @@ tbody tr:hover {
.topbar-right {
gap: 8px;
+ align-items: stretch;
}
.search {
@@ -1339,7 +1377,53 @@ tbody tr:hover {
}
.action-row .btn,
- .btn {
+ .auth-actions .btn {
+ width: 100%;
+ }
+
+ .workspace-switch {
+ padding: 10px 12px;
+ }
+
+ .workspace-switch strong {
+ font-size: 12px;
+ }
+
+ .workspace-switch span {
+ font-size: 11px;
+ }
+
+ .topbar-left .chip-row {
+ gap: 6px;
+ }
+
+ .topbar-left .chip,
+ .top-pill {
+ font-size: 11px;
+ }
+
+ .topbar-right > :not(.avatar) {
+ width: 100%;
+ }
+
+ .topbar-right .search {
+ order: 2;
+ }
+
+ .topbar-right .auth-inline {
+ order: 1;
+ }
+
+ .topbar-right .top-pill {
+ width: auto;
+ }
+
+ .topbar-right .avatar {
+ order: 4;
+ align-self: flex-end;
+ }
+
+ .auth-inline .btn {
width: 100%;
}
@@ -1383,39 +1467,3 @@ tbody tr:hover {
font-size: 12px;
text-align: right;
}
-
-@media (max-width: 1320px) {
- .grid-main,
- .grid-split,
- .grid-5,
- .grid-4,
- .grid-3,
- .three-col,
- .two-col {
- grid-template-columns: 1fr;
- }
- .calendar {
- grid-template-columns: repeat(2, minmax(0, 1fr));
- }
-}
-
-@media (max-width: 1080px) {
- .app-shell {
- grid-template-columns: 1fr;
- }
- .sidebar {
- position: relative;
- height: auto;
- }
- .topbar {
- flex-direction: column;
- align-items: stretch;
- }
- .topbar-left,
- .topbar-right {
- flex-wrap: wrap;
- }
- .search {
- min-width: 0;
- }
-}