feat: refine mobile project sheets
This commit is contained in:
@@ -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("请填写项目名称");
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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/);
|
||||
|
||||
Reference in New Issue
Block a user