Skip to content

Commit 40d3948

Browse files
committed
feat: adapt subagent manager for mobile
1 parent 5c417e3 commit 40d3948

3 files changed

Lines changed: 202 additions & 14 deletions

File tree

apps/kimi-code/src/components/CustomAgentManagerDialog.tsx

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {
22
AlertCircle,
3+
ArrowLeft,
34
Bot,
45
Check,
56
FileCode2,
@@ -62,6 +63,7 @@ export function CustomAgentManagerDialog({
6263
const [error, setError] = useState<string>();
6364
const [notice, setNotice] = useState<string>();
6465
const [confirmDelete, setConfirmDelete] = useState(false);
66+
const [mobilePane, setMobilePane] = useState<"list" | "editor">("list");
6567

6668
const dirty = Boolean(draft && draft.content !== draft.originalContent);
6769
const scopedAgents = useMemo(
@@ -153,6 +155,7 @@ export function CustomAgentManagerDialog({
153155
const selectScope = (scope: CustomAgentScope): void => {
154156
if (scope === activeScope || !confirmDiscard()) return;
155157
setActiveScope(scope);
158+
setMobilePane("list");
156159
setNotice(undefined);
157160
setError(undefined);
158161
const first = agents.find((agent) => agent.scope === scope);
@@ -172,7 +175,11 @@ export function CustomAgentManagerDialog({
172175

173176
const selectAgent = (agent: CustomAgentDescriptor): void => {
174177
const key = customAgentKey(agent);
175-
if (key === selectedKey || !confirmDiscard()) return;
178+
if (key === selectedKey) {
179+
setMobilePane("editor");
180+
return;
181+
}
182+
if (!confirmDiscard()) return;
176183
setSelectedKey(key);
177184
setDraft({
178185
scope: agent.scope,
@@ -183,6 +190,7 @@ export function CustomAgentManagerDialog({
183190
setNotice(undefined);
184191
setError(undefined);
185192
setConfirmDelete(false);
193+
setMobilePane("editor");
186194
};
187195

188196
const createAgent = (): void => {
@@ -197,6 +205,7 @@ export function CustomAgentManagerDialog({
197205
setNotice(undefined);
198206
setError(undefined);
199207
setConfirmDelete(false);
208+
setMobilePane("editor");
200209
window.setTimeout(() => editorRef.current?.focus(), 0);
201210
};
202211

@@ -239,6 +248,7 @@ export function CustomAgentManagerDialog({
239248
setConfirmDelete(false);
240249
setSelectedKey(undefined);
241250
setDraft(undefined);
251+
setMobilePane("list");
242252
setNotice(t("agents.deleted"));
243253
await loadAgents(undefined, activeScope);
244254
} catch (nextError) {
@@ -253,6 +263,25 @@ export function CustomAgentManagerDialog({
253263
void loadAgents(selectedKey, activeScope);
254264
};
255265

266+
const showAgentList = (): void => {
267+
if (!confirmDiscard()) return;
268+
if (!draft?.relativePath) {
269+
setSelectedKey(undefined);
270+
setDraft(undefined);
271+
} else if (selectedAgent) {
272+
setDraft({
273+
scope: selectedAgent.scope,
274+
relativePath: selectedAgent.relativePath,
275+
content: selectedAgent.content,
276+
originalContent: selectedAgent.content,
277+
});
278+
}
279+
setError(undefined);
280+
setNotice(undefined);
281+
setConfirmDelete(false);
282+
setMobilePane("list");
283+
};
284+
256285
const handleEditorKeyDown = (
257286
event: ReactKeyboardEvent<HTMLTextAreaElement>,
258287
): void => {
@@ -332,7 +361,7 @@ export function CustomAgentManagerDialog({
332361
</button>
333362
</div>
334363

335-
<div className="agent-manager-body">
364+
<div className={`agent-manager-body ${mobilePane === "editor" ? "mobile-editor-open" : ""}`}>
336365
<aside className="agent-manager-list-pane">
337366
<div className="agent-manager-list-heading">
338367
<div>
@@ -387,7 +416,15 @@ export function CustomAgentManagerDialog({
387416
{draft ? (
388417
<>
389418
<div className="agent-manager-editor-heading">
390-
<div>
419+
<button
420+
className="agent-manager-mobile-back"
421+
type="button"
422+
aria-label={t("agents.backToList")}
423+
onClick={showAgentList}
424+
>
425+
<ArrowLeft size={18} />
426+
</button>
427+
<div className="agent-manager-editor-meta">
391428
<span>{draft.relativePath ? selectedAgent?.name ?? draft.relativePath : t("agents.untitled")}</span>
392429
<small>{draft.relativePath ? selectedAgent?.path : t("agents.newHint")}</small>
393430
</div>

apps/kimi-code/src/i18n.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,7 @@ const zh = {
323323
"agents.title": "自定义子代理",
324324
"agents.subtitle": "为整个应用或当前项目定义可复用的专业代理",
325325
"agents.close": "关闭子代理管理",
326+
"agents.backToList": "返回子代理列表",
326327
"agents.scopes": "子代理作用域",
327328
"agents.scopeApp": "应用级",
328329
"agents.scopeProject": "当前项目",
@@ -1015,6 +1016,7 @@ const en: Record<TranslationKey, string> = {
10151016
"agents.title": "Custom subagents",
10161017
"agents.subtitle": "Define reusable specialist agents for the app or this project",
10171018
"agents.close": "Close subagent manager",
1019+
"agents.backToList": "Back to subagent list",
10181020
"agents.scopes": "Subagent scopes",
10191021
"agents.scopeApp": "Application",
10201022
"agents.scopeProject": "Current project",

apps/kimi-code/src/styles/agents.css

Lines changed: 160 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -367,14 +367,18 @@
367367
border-bottom: 0.5px solid var(--line);
368368
}
369369

370-
.agent-manager-editor-heading > div:first-child {
370+
.agent-manager-mobile-back {
371+
display: none;
372+
}
373+
374+
.agent-manager-editor-meta {
371375
display: flex;
372376
min-width: 0;
373377
flex-direction: column;
374378
gap: 3px;
375379
}
376380

377-
.agent-manager-editor-heading > div:first-child span {
381+
.agent-manager-editor-meta > span {
378382
font-family: "DM Mono", monospace;
379383
font-size: 12px;
380384
font-weight: 500;
@@ -601,42 +605,187 @@
601605
gap: 8px;
602606
}
603607

604-
@media (max-width: 720px) {
608+
@media (max-width: 760px) {
605609
.agent-manager-backdrop {
606610
padding: 0;
607611
}
608612

609613
.agent-manager-dialog {
610614
width: 100vw;
611-
height: 100vh;
615+
height: 100dvh;
612616
min-height: 0;
613617
border: 0;
614618
border-radius: 0;
615619
}
616620

621+
.agent-manager-header {
622+
min-height: calc(58px + env(safe-area-inset-top));
623+
padding: env(safe-area-inset-top) 12px 0 14px;
624+
}
625+
626+
.agent-manager-title {
627+
gap: 9px;
628+
}
629+
630+
.agent-manager-title-icon {
631+
width: 32px;
632+
height: 32px;
633+
}
634+
635+
.agent-manager-close {
636+
width: 44px;
637+
height: 44px;
638+
}
639+
617640
.agent-manager-title p,
618641
.agent-manager-scope-tabs em {
619642
display: none;
620643
}
621644

645+
.agent-manager-scope-tabs {
646+
min-height: 46px;
647+
padding: 0 14px;
648+
overflow-x: auto;
649+
gap: 20px;
650+
scrollbar-width: none;
651+
}
652+
653+
.agent-manager-scope-tabs::-webkit-scrollbar {
654+
display: none;
655+
}
656+
657+
.agent-manager-scope-tabs button {
658+
min-height: 46px;
659+
flex: 0 0 auto;
660+
}
661+
622662
.agent-manager-body {
623-
grid-template-columns: 1fr;
624-
grid-template-rows: minmax(150px, 30vh) minmax(0, 1fr);
663+
position: relative;
664+
display: block;
625665
}
626666

627667
.agent-manager-list-pane {
668+
height: 100%;
669+
padding: 12px 10px max(12px, env(safe-area-inset-bottom));
628670
border-right: 0;
629-
border-bottom: 0.5px solid var(--line);
671+
}
672+
673+
.agent-manager-body:not(.mobile-editor-open) .agent-manager-editor-pane,
674+
.agent-manager-body.mobile-editor-open .agent-manager-list-pane {
675+
display: none;
676+
}
677+
678+
.agent-manager-list-heading {
679+
min-height: 48px;
680+
padding-right: 8px;
681+
padding-left: 8px;
682+
}
683+
684+
.agent-manager-list-heading button {
685+
width: 44px;
686+
height: 44px;
687+
}
688+
689+
.agent-manager-list-item {
690+
min-height: 60px;
691+
padding: 9px 10px;
692+
}
693+
694+
.agent-manager-new {
695+
min-height: 44px;
696+
}
697+
698+
.agent-manager-editor-pane {
699+
height: 100%;
630700
}
631701

632702
.agent-manager-editor-heading {
633-
padding-right: 12px;
634-
padding-left: 12px;
703+
min-height: 56px;
704+
padding: 8px 12px 8px 8px;
705+
justify-content: flex-start;
706+
}
707+
708+
.agent-manager-mobile-back {
709+
display: grid;
710+
width: 44px;
711+
height: 44px;
712+
padding: 0;
713+
flex: 0 0 auto;
714+
place-items: center;
715+
border: 0;
716+
border-radius: 9px;
717+
color: var(--muted);
718+
background: transparent;
719+
}
720+
721+
.agent-manager-mobile-back:active {
722+
color: var(--text);
723+
background: var(--hover);
724+
}
725+
726+
.agent-manager-editor-meta {
727+
flex: 1;
728+
}
729+
730+
.agent-manager-editor-heading small {
731+
max-width: calc(100vw - 150px);
732+
}
733+
734+
.agent-manager-message {
735+
margin: 8px 10px 0;
635736
}
636737

637738
.agent-manager-editor {
638739
width: calc(100% - 20px);
639-
margin-right: 10px;
640-
margin-left: 10px;
740+
margin: 8px 10px 0;
741+
padding: 13px 14px;
742+
border-radius: 9px;
743+
font-size: 16px;
744+
line-height: 1.55;
745+
}
746+
747+
.agent-manager-editor-footer {
748+
min-height: 28px;
749+
padding: 0 12px;
750+
justify-content: flex-end;
751+
}
752+
753+
.agent-manager-editor-footer > span:first-child {
754+
display: none;
755+
}
756+
757+
.agent-manager-actions {
758+
min-height: calc(58px + env(safe-area-inset-bottom));
759+
padding: 8px 10px max(8px, env(safe-area-inset-bottom));
760+
}
761+
762+
.agent-manager-actions button,
763+
.agent-manager-editor-empty button,
764+
.agent-manager-confirm button {
765+
min-height: 44px;
766+
padding-right: 14px;
767+
padding-left: 14px;
768+
}
769+
770+
.agent-manager-editor-empty {
771+
padding: 24px;
772+
}
773+
774+
.agent-manager-confirm-backdrop {
775+
padding: 16px;
776+
padding-bottom: max(16px, env(safe-area-inset-bottom));
777+
}
778+
779+
.agent-manager-confirm {
780+
width: 100%;
781+
}
782+
783+
.agent-manager-confirm > div,
784+
.agent-manager-confirm button {
785+
width: 100%;
786+
}
787+
788+
.agent-manager-confirm > div {
789+
flex-direction: column-reverse;
641790
}
642791
}

0 commit comments

Comments
 (0)