import "package:flutter/widgets.dart"; import "package:shadcn_flutter/shadcn_flutter.dart" as shad; // floating pane visual — use inside showDialog, backdrop handled by caller class PaneDialog extends StatelessWidget { const PaneDialog({ required this.title, required this.child, this.onClose, this.fillHeight = false, super.key, }); final String title; final Widget child; final VoidCallback? onClose; final bool fillHeight; @override Widget build(BuildContext context) { final scheme = shad.Theme.of(context).colorScheme; final borderColor = Color.lerp(scheme.border, scheme.foreground, 0.1)!; return DecoratedBox( decoration: BoxDecoration( color: scheme.background, borderRadius: BorderRadius.circular(8), boxShadow: const [ BoxShadow(color: Color(0x26888888), blurRadius: 4, spreadRadius: 2), ], ), child: Stack( children: [ ClipRRect( borderRadius: BorderRadius.circular(8), child: Column( mainAxisSize: fillHeight ? MainAxisSize.max : MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ _TitleBar(title: title, borderColor: borderColor, onClose: onClose), child, ], ), ), Positioned.fill( child: IgnorePointer( child: DecoratedBox( decoration: BoxDecoration( borderRadius: BorderRadius.circular(8), border: Border.all(color: borderColor, width: 1), ), ), ), ), ], ), ); } } class _TitleBar extends StatelessWidget { const _TitleBar({ required this.title, required this.borderColor, this.onClose, }); final String title; final Color borderColor; final VoidCallback? onClose; @override Widget build(BuildContext context) { final scheme = shad.Theme.of(context).colorScheme; return Container( height: 34, padding: const EdgeInsets.symmetric(horizontal: 10), decoration: BoxDecoration( color: scheme.secondary, borderRadius: const BorderRadius.only( topLeft: Radius.circular(8), topRight: Radius.circular(8), ), border: Border(bottom: BorderSide(color: borderColor, width: 1)), ), child: Row( children: [ Text( title, style: shad.TextStyle( color: scheme.secondaryForeground, fontSize: 12, fontWeight: FontWeight.w600, ), ), const Spacer(), if (onClose != null) _CloseBtn(onTap: onClose!), ], ), ); } } class _CloseBtn extends StatefulWidget { const _CloseBtn({required this.onTap}); final VoidCallback onTap; @override State<_CloseBtn> createState() => _CloseBtnState(); } class _CloseBtnState extends State<_CloseBtn> { bool _hovered = false; @override Widget build(BuildContext context) { final scheme = shad.Theme.of(context).colorScheme; return MouseRegion( onEnter: (_) => setState(() => _hovered = true), onExit: (_) => setState(() => _hovered = false), child: GestureDetector( onTap: widget.onTap, child: TweenAnimationBuilder( tween: Tween(begin: 0, end: _hovered ? 1.0 : 0.0), duration: const Duration(milliseconds: 20), builder: (context, t, _) { return Container( width: 18, height: 18, decoration: BoxDecoration( color: Color.lerp( const Color(0x00000000), scheme.destructive.withValues(alpha: 0.12), t, ), borderRadius: BorderRadius.circular(4), ), child: shad.Icon( shad.LucideIcons.x, size: 13, color: Color.lerp(scheme.mutedForeground, scheme.destructive, t), ), ); }, ), ), ); } }