feat(tui): allow collapsing archived todo panels
This commit is contained in:
parent
c78b528125
commit
b36007b246
@ -26,7 +26,7 @@ module.exports = {
|
||||
],
|
||||
// We feed already-compiled JS into babel; don't re-parse as TS/JSX.
|
||||
// @babel/preset-env etc. would over-transform — the compiler is our only
|
||||
// transform here.
|
||||
babelrc: false,
|
||||
configFile: false
|
||||
// transform here. babelrc:false stops @babel/cli from walking up the
|
||||
// filesystem looking for other configs (the parent repo might add one).
|
||||
babelrc: false
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ import typescriptEslint from '@typescript-eslint/eslint-plugin'
|
||||
import typescriptParser from '@typescript-eslint/parser'
|
||||
import perfectionist from 'eslint-plugin-perfectionist'
|
||||
import reactPlugin from 'eslint-plugin-react'
|
||||
import reactCompiler from 'eslint-plugin-react-compiler'
|
||||
import hooksPlugin from 'eslint-plugin-react-hooks'
|
||||
import unusedImports from 'eslint-plugin-unused-imports'
|
||||
import globals from 'globals'
|
||||
@ -43,6 +44,7 @@ export default [
|
||||
'custom-rules': customRules,
|
||||
perfectionist,
|
||||
react: reactPlugin,
|
||||
'react-compiler': reactCompiler,
|
||||
'react-hooks': hooksPlugin,
|
||||
'unused-imports': unusedImports
|
||||
},
|
||||
@ -53,6 +55,12 @@ export default [
|
||||
'@typescript-eslint/no-unused-vars': 'off',
|
||||
'no-undef': 'off',
|
||||
'no-unused-vars': 'off',
|
||||
// React Compiler: warn (not error) so the gate doesn't block merges
|
||||
// while we migrate. Flags patterns that would break the compiler at
|
||||
// runtime (mutating refs during render, non-PascalCase components,
|
||||
// etc.). See audit §5 — we run the compiler in `npm run build` as a
|
||||
// post-pass over tsc's `dist/` output.
|
||||
'react-compiler/react-compiler': 'warn',
|
||||
'padding-line-between-statements': [
|
||||
1,
|
||||
{ blankLine: 'always', next: ['block-like', 'block', 'return', 'if', 'class', 'continue', 'debugger', 'break', 'multiline-const', 'multiline-let'], prev: '*' },
|
||||
@ -89,6 +97,9 @@ export default [
|
||||
'no-constant-condition': 'off',
|
||||
'no-empty': 'off',
|
||||
'no-redeclare': 'off',
|
||||
// Ink internals: reconciler, style pool, DOM node impl — full of
|
||||
// intentional side effects the compiler rules reject.
|
||||
'react-compiler/react-compiler': 'off',
|
||||
'react-hooks/exhaustive-deps': 'off'
|
||||
}
|
||||
},
|
||||
|
||||
@ -6,7 +6,8 @@
|
||||
"scripts": {
|
||||
"dev": "npm run build --prefix packages/hermes-ink && tsx --watch src/entry.tsx",
|
||||
"start": "tsx src/entry.tsx",
|
||||
"build": "npm run build --prefix packages/hermes-ink && tsc -p tsconfig.build.json && chmod +x dist/entry.js",
|
||||
"build": "npm run build --prefix packages/hermes-ink && tsc -p tsconfig.build.json && npm run build:compile && chmod +x dist/entry.js",
|
||||
"build:compile": "babel dist --out-dir dist --config-file ./babel.compiler.config.cjs --extensions .js --keep-file-extension",
|
||||
"type-check": "tsc --noEmit -p tsconfig.json",
|
||||
"lint": "eslint src/ packages/",
|
||||
"lint:fix": "eslint src/ packages/ --fix",
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { Box, Text } from '@hermes/ink'
|
||||
import { memo } from 'react'
|
||||
import { memo, useState } from 'react'
|
||||
|
||||
import { countPendingTodos } from '../lib/liveProgress.js'
|
||||
import { todoGlyph, todoTone } from '../lib/todo.js'
|
||||
@ -13,7 +13,7 @@ const rowColor = (t: Theme, status: TodoItem['status']) => {
|
||||
}
|
||||
|
||||
export const TodoPanel = memo(function TodoPanel({
|
||||
collapsed = false,
|
||||
collapsed,
|
||||
incomplete = false,
|
||||
onToggle,
|
||||
t,
|
||||
@ -25,6 +25,25 @@ export const TodoPanel = memo(function TodoPanel({
|
||||
t: Theme
|
||||
todos: TodoItem[]
|
||||
}) {
|
||||
// Fallback local state for archived todos in transcript where there's no
|
||||
// external controller. Live TodoPanel passes collapsed+onToggle from the
|
||||
// turn store so clicks still work there.
|
||||
const [localCollapsed, setLocalCollapsed] = useState(false)
|
||||
const isControlled = typeof collapsed === 'boolean'
|
||||
const effectiveCollapsed = isControlled ? collapsed : localCollapsed
|
||||
|
||||
const handleToggle = () => {
|
||||
if (onToggle) {
|
||||
onToggle()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (!isControlled) {
|
||||
setLocalCollapsed(v => !v)
|
||||
}
|
||||
}
|
||||
|
||||
if (!todos.length) {
|
||||
return null
|
||||
}
|
||||
@ -34,9 +53,9 @@ export const TodoPanel = memo(function TodoPanel({
|
||||
|
||||
return (
|
||||
<Box flexDirection="column" marginBottom={1}>
|
||||
<Box onClick={onToggle}>
|
||||
<Box onClick={handleToggle}>
|
||||
<Text color={t.color.dim}>
|
||||
<Text color={t.color.amber}>{collapsed ? '▸ ' : '▾ '}</Text>
|
||||
<Text color={t.color.amber}>{effectiveCollapsed ? '▸ ' : '▾ '}</Text>
|
||||
<Text bold color={t.color.cornsilk}>
|
||||
Todo
|
||||
</Text>{' '}
|
||||
@ -52,7 +71,7 @@ export const TodoPanel = memo(function TodoPanel({
|
||||
</Text>
|
||||
</Box>
|
||||
|
||||
{!collapsed && (
|
||||
{!effectiveCollapsed && (
|
||||
<Box flexDirection="column" marginLeft={2}>
|
||||
{todos.map(todo => {
|
||||
const tone = todoTone(todo.status)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user