sweep ClideTappable across 15 files, remove 267 lines

23 StatefulWidget+State hover pairs converted to StatelessWidget
using ClideTappable(builder: (ctx, hovered, _) => ...). Covers
app.dart (5), welcome (2), claude session host (2), column hat (2),
spine (1), pane chrome (1), tab bar (1), decisions (1), tickets (1),
graph (1), pql panel (1), backlinks (1), file tree (2), git panel (1),
git status (1). Only EditorDragHandle and ClidePalette excluded
(drag/keyboard behavior beyond hover+tap).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-23 11:28:35 +02:00
co-authored by Claude Opus 4.6
parent fbd5f1ae04
commit cf3e7700a3
15 changed files with 416 additions and 683 deletions
+18 -31
View File
@@ -140,31 +140,22 @@ class _LinkGroup extends StatelessWidget {
}
}
class _LinkRow extends StatefulWidget {
class _LinkRow extends StatelessWidget {
const _LinkRow({required this.link, required this.pathKey});
final Map<String, Object?> link;
final String pathKey;
@override
State<_LinkRow> createState() => _LinkRowState();
}
class _LinkRowState extends State<_LinkRow> {
bool _hover = false;
@override
Widget build(BuildContext context) {
final tokens = ClideTheme.of(context).surface;
final target = widget.link[widget.pathKey] as String? ?? '';
final alias = widget.link['alias'] as String?;
final target = link[pathKey] as String? ?? '';
final alias = link['alias'] as String?;
final display = alias ?? target;
return MouseRegion(
cursor: SystemMouseCursors.click,
onEnter: (_) => setState(() => _hover = true),
onExit: (_) => setState(() => _hover = false),
child: GestureDetector(
behavior: HitTestBehavior.opaque,
return Semantics(
button: true,
label: target,
child: ClideTappable(
onTap: () {
if (!target.startsWith('http')) {
final kernel = ClideKernel.of(context);
@@ -172,21 +163,17 @@ class _LinkRowState extends State<_LinkRow> {
kernel.ipc.request('editor.open', args: {'path': target}));
}
},
child: Semantics(
button: true,
label: target,
child: Container(
color: _hover ? tokens.sidebarItemHover : null,
padding:
const EdgeInsets.symmetric(horizontal: 20, vertical: 2),
child: ClideText(
display,
maxLines: 1,
overflow: TextOverflow.ellipsis,
color: target.startsWith('http')
? tokens.statusInfo
: tokens.sidebarForeground,
),
builder: (context, hovered, _) => Container(
color: hovered ? tokens.sidebarItemHover : null,
padding:
const EdgeInsets.symmetric(horizontal: 20, vertical: 2),
child: ClideText(
display,
maxLines: 1,
overflow: TextOverflow.ellipsis,
color: target.startsWith('http')
? tokens.statusInfo
: tokens.sidebarForeground,
),
),
),
+15 -28
View File
@@ -155,45 +155,32 @@ class _ViewTabs extends StatelessWidget {
};
}
class _FileRow extends StatefulWidget {
class _FileRow extends StatelessWidget {
const _FileRow({required this.entry});
final Map<String, Object?> entry;
@override
State<_FileRow> createState() => _FileRowState();
}
class _FileRowState extends State<_FileRow> {
bool _hover = false;
@override
Widget build(BuildContext context) {
final tokens = ClideTheme.of(context).surface;
final path = widget.entry['path'] as String? ?? '';
final name = widget.entry['name'] as String? ?? path.split('/').last;
return MouseRegion(
cursor: SystemMouseCursors.click,
onEnter: (_) => setState(() => _hover = true),
onExit: (_) => setState(() => _hover = false),
child: GestureDetector(
behavior: HitTestBehavior.opaque,
final path = entry['path'] as String? ?? '';
final name = entry['name'] as String? ?? path.split('/').last;
return Semantics(
button: true,
label: 'Open $name',
child: ClideTappable(
onTap: () {
final kernel = ClideKernel.of(context);
unawaited(
kernel.ipc.request('editor.open', args: {'path': path}));
},
child: Semantics(
button: true,
label: 'Open $name',
child: Container(
color: _hover ? tokens.sidebarItemHover : null,
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 3),
child: ClideText(
path,
maxLines: 1,
overflow: TextOverflow.ellipsis,
color: tokens.sidebarForeground,
),
builder: (context, hovered, _) => Container(
color: hovered ? tokens.sidebarItemHover : null,
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 3),
child: ClideText(
path,
maxLines: 1,
overflow: TextOverflow.ellipsis,
color: tokens.sidebarForeground,
),
),
),