feat: refine mobile project sheets

This commit is contained in:
kris
2026-03-30 11:48:36 +08:00
parent 28863b208e
commit a50d1b00f1
3 changed files with 62 additions and 2 deletions

View File

@@ -3145,7 +3145,12 @@ function openDashboardProjectSwitcher() {
const reviewCount = getProjectReviews(project.id).length;
const isActive = project.id === selectedProject?.id;
return `
<div class="task-item compact" style="${isActive ? "border-color:rgba(59, 130, 246, 0.32); background:linear-gradient(180deg, rgba(239, 246, 255, 0.98) 0%, rgba(255,255,255,0.98) 100%);" : ""}">
<button
class="task-item compact project-choice-card ${isActive ? "active" : ""}"
type="button"
data-project-choice="${escapeHtml(project.id)}"
style="${isActive ? "border-color:rgba(59, 130, 246, 0.32); background:linear-gradient(180deg, rgba(239, 246, 255, 0.98) 0%, rgba(255,255,255,0.98) 100%);" : ""}"
>
<h4>${escapeHtml(project.name || "未命名项目")}</h4>
<p>${escapeHtml(project.description || "还没有补项目说明,适合先切过去继续完善。")}</p>
<div class="task-meta">
@@ -3154,7 +3159,7 @@ function openDashboardProjectSwitcher() {
<span class="tag">Agent ${escapeHtml(formatNumber(stats.assistants.length))}</span>
<span class="tag">复盘 ${escapeHtml(formatNumber(reviewCount))}</span>
</div>
</div>
</button>
`;
}).join("");
openActionModal({
@@ -3187,6 +3192,18 @@ function openDashboardProjectSwitcher() {
},
{ name: "projectId", label: "当前项目", type: "select", value: getSelectedProject()?.id || "", options }
],
onOpen: ({ fields }) => {
const select = fields.querySelector('[data-action-field="projectId"]');
fields.querySelectorAll("[data-project-choice]").forEach((button) => {
button.addEventListener("click", () => {
if (select) {
select.value = button.dataset.projectChoice || "";
}
fields.querySelectorAll("[data-project-choice]").forEach((item) => item.classList.remove("active"));
button.classList.add("active");
});
});
},
onSubmit: async (payload) => {
appState.selectedProjectId = payload.projectId || "";
setBusy(true, "正在切换项目视图...");
@@ -7164,6 +7181,9 @@ async function createProject() {
{ name: "name", label: "项目名称", placeholder: "例如:创业 IP 增长实验室" },
{ name: "description", label: "项目说明", type: "textarea", rows: 4, placeholder: "写一句这个项目主要解决什么问题、接下来准备推进什么" }
],
onOpen: ({ fields }) => {
fields.querySelector('[data-action-field="name"]')?.focus();
},
onSubmit: async (values) => {
const name = String(values.name || "").trim();
if (!name) throw new Error("请填写项目名称");

View File

@@ -1468,6 +1468,20 @@ select {
padding: 14px;
}
.project-choice-card {
width: 100%;
display: grid;
gap: 8px;
text-align: left;
cursor: pointer;
appearance: none;
}
.project-choice-card:hover {
border-color: rgba(79, 143, 238, 0.24);
box-shadow: inset 0 0 0 1px rgba(79, 143, 238, 0.08);
}
.detail-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
@@ -2212,6 +2226,21 @@ tbody tr:hover {
padding-inline: 14px;
}
.field-stack input,
.field-stack textarea,
.field-stack select {
min-height: 46px;
font-size: 16px;
}
.field-stack textarea {
min-height: 108px;
}
.project-choice-card {
min-height: 96px;
}
.page-detail-tabs {
flex-wrap: nowrap;
overflow-x: auto;

View File

@@ -114,6 +114,17 @@ test("project creation and switching use in-app sheets instead of browser prompt
assert.match(projectSwitcher, /切换到这个项目/);
});
test("mobile project sheets support direct project picking and zoom-safe form controls", () => {
const projectSwitcher = extractBetween(APP, "function openDashboardProjectSwitcher()", "function openDashboardActionReasonAction(");
const createProject = extractBetween(APP, "async function createProject()", "function openPreferredModelAction()");
assert.match(projectSwitcher, /data-project-choice=/);
assert.match(projectSwitcher, /onOpen:\s*\(/);
assert.match(projectSwitcher, /select\.value = button\.dataset\.projectChoice/);
assert.match(createProject, /onOpen:\s*\(/);
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.field-stack input,\s*[\s\S]*\.field-stack textarea,\s*[\s\S]*\.field-stack select\s*\{[\s\S]*min-height:\s*46px/);
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.field-stack input,\s*[\s\S]*\.field-stack textarea,\s*[\s\S]*\.field-stack select\s*\{[\s\S]*font-size:\s*16px/);
});
test("mobile touch targets raise tappable buttons, tabs, and action tags closer to native sizes", () => {
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.btn,\s*[\s\S]*\.tab,\s*[\s\S]*\.tag\.clickable-tag\s*\{[\s\S]*min-height:\s*44px/);
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.btn,\s*[\s\S]*\.tab,\s*[\s\S]*\.tag\.clickable-tag\s*\{[\s\S]*display:\s*inline-flex/);