| name | eisland-dev-add-empty-state |
| description | 为 eIsland 灵动岛添加一个新的空白状态机(IslandState)。当用户要求创建新状态、新页面、 新界面(如登录页、设置子页面、独立面板)时使用此 skill。即使用户只说"加个新状态"或 "创建一个 XX 页面",也应触发。此 skill 覆盖从类型注册、窗口尺寸、CSS 样式到鼠标交互 行为的全部 12 个修改点,确保状态机完整可用。
|
eIsland: 添加空白状态机
为灵动岛添加一个新的空白 IslandState,使其具备正确的窗口大小、样式和交互行为。
前置确认
在开始前,向用户确认以下信息:
- 状态名称 — kebab-case 标识符(如
musicProvidersLogin、settings wizard)
- 窗口大小 — 选择一种预设:
maxExpand(860x400)— 全展开大面板,适合设置、表单、内容页
expanded(860x150)— 单击展开面板
hover(500x60)— 悬停小面板
notification(500x88)— 通知面板
lyrics(500x42)— 歌词条
- 自定义尺寸
- 鼠标移出后是否收回? — 必须主动询问:
"鼠标移出灵动岛后,是否自动收回至待机状态?(大多数独立页面如登录、注册、支付页面选择不收回)"
- 不收回(推荐用于独立页面)→ 需要额外修改
AUTH_STATES、useIslandHoverInteraction.ts、useIslandSettingsSync.ts
- 收回 → 无需额外修改
- 是否为认证/登录类页面? — 如果是,需要导入
auth.css 并使用 auth-state-content 类名
实现步骤
Step 1: 注册类型
文件: src/renderer/store/types/index.ts
1a. 在 IslandState 联合类型末尾添加新状态名:
export type IslandState = '...' | 'newStateName';
1b. 在 IslandSlice 接口中添加 setter 方法签名:
setNewStateName: () => void;
Step 2: 实现 setter
文件: src/renderer/store/slices/islandSlice.ts
在已有的 setter 群(如 setBindEmail 之后)添加新 setter:
setNewStateName: () => set((prev) => {
if (prev.uiStateLocked && prev.state !== 'newStateName') return prev;
const standalone = isStandaloneRenderer();
if (!standalone) {
window.api?.expandWindowSettings();
window.api?.disableMousePassthrough();
}
const nextAuthReturnState = ( || prev.state === 'newStateName')
? prev.authReturnState
: (standalone ? 'maxExpand' : prev.state);
return { state: 'newStateName' as never, authReturnState: nextAuthReturnState };
}),
2b. 在 setIdle 的守卫条件中添加新状态(防止被强制收回):
if (!force && (... || prev.state === 'newStateName')) return prev;
2c. 在 returnFromAuth 中:
- 窗口展开分支(
else if (target === ...))添加新状态
authStates 数组中添加新状态
Step 3: 窗口面积配置
文件: src/renderer/store/constants/islandTransition.ts
在 ISLAND_STATE_AREA 中添加条目(值与所选窗口大小一致):
newStateName: 860 * 400,
Step 4: 状态行为配置
文件: src/renderer/components/config/dynamicIslandStateConfig.ts
在 STATE_CONFIGS 中添加条目:
newStateName: {
name: 'newStateName',
mousePassthrough: false,
expanded: true,
enterDelay: 0,
leaveDelay: 0,
},
Step 5: 创建状态组件
5a. 创建目录 src/renderer/components/states/newStateName/
5b. 创建 NewStateNameContent.tsx:
import type { ReactElement } from 'react';
export function NewStateNameContent(): ReactElement {
return <div />;
}
5c. 创建 index.ts:
export { NewStateNameContent } from './NewStateNameContent';
Step 6: 注册渲染
6a. src/renderer/components/components/DynamicIslandStateContent.tsx:
import { NewStateNameContent } from '../states/newStateName';
if (state === 'newStateName') return <NewStateNameContent />;
6b. src/renderer/components/components/StandaloneWindowViewport.tsx:
import { NewStateNameContent } from '../states/newStateName';
{activeTab === 'settings' && state === 'newStateName' && <NewStateNameContent />}
{activeTab === 'settings' && state !== '...' && state !== 'newStateName' && <SettingsTab />}
Step 7: CSS 窗口尺寸
文件: src/renderer/styles/shell/shell.css
将新状态添加到对应尺寸的选择器组中。例如 maxExpand 尺寸:
.island-shell.login,
.island-shell.register,
.island-shell.newStateName {
width: 860px;
height: 400px;
background: var(--color-island-bg);
border-radius: 0 0 22px 22px;
box-shadow: none;
}
同时添加 ::before 伪元素规则(隐藏光泽层):
.island-shell.login::before,
.island-shell.newStateName::before {
opacity: 0;
pointer-events: none;
}
Step 8: 认证类页面样式(如适用)
文件: src/renderer/styles/auth/auth.css
将新状态添加到 auth 动画选择器组:
.island-shell.login .auth-state-content,
.island-shell.newStateName .auth-state-content {
align-items: center;
padding: 14px 22px;
}
Step 9: 鼠标移出不收回(如适用)
如果用户确认需要"鼠标移出后不收回",修改以下 3 个文件:
9a. src/renderer/components/hooks/useIslandHoverInteraction.ts:
AUTH_STATES 集合添加新状态
- 第 134 行的状态检查列表添加新状态
9b. src/renderer/components/hooks/useIslandSettingsSync.ts:
Step 10: 验证
npx tsc --noEmit --skipLibCheck
文件清单
完成所有步骤后,验证以下文件已被修改: