From 1cc6d22f205291c70772be51f2275a30555c954c Mon Sep 17 00:00:00 2001 From: Patrick Britton Date: Sun, 1 Feb 2026 13:36:02 -0600 Subject: [PATCH] Redesign previous chain box with rounded top, flat bottom, and gradient effect - Move previous chain box to sit directly on top of current post - Add rounded top corners with flat bottom for visual flow - Implement gradient from darker top to lighter bottom - Add subtle top border for better visual separation - Update arrow icon styling with background container - Remove spacing between previous chain and focus post --- .../lib/widgets/kinetic_thread_widget.dart | 152 ++++++++++-------- 1 file changed, 83 insertions(+), 69 deletions(-) diff --git a/sojorn_app/lib/widgets/kinetic_thread_widget.dart b/sojorn_app/lib/widgets/kinetic_thread_widget.dart index 8906c59..458670e 100644 --- a/sojorn_app/lib/widgets/kinetic_thread_widget.dart +++ b/sojorn_app/lib/widgets/kinetic_thread_widget.dart @@ -496,88 +496,102 @@ class _KineticThreadWidgetState extends ConsumerState } Widget _buildPreviousChainJump(ThreadNode parentNode) { - return Padding( - padding: const EdgeInsets.fromLTRB(16, 12, 16, 6), + return Container( + margin: const EdgeInsets.fromLTRB(16, 0, 16, 0), child: GestureDetector( onTap: () { if (_layerStack.length > 1) { _scrubToLayer(_layerStack.length - 2); } }, - child: ClipRRect( - borderRadius: BorderRadius.circular(16), - child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: 8, sigmaY: 8), - child: Container( - width: double.infinity, - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: Colors.white.withValues(alpha: 0.5), - borderRadius: BorderRadius.circular(16), - border: Border.all( - color: AppTheme.navyBlue.withValues(alpha: 0.12), + child: Container( + width: double.infinity, + decoration: BoxDecoration( + // Rounded top corners, flat bottom + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(20), + topRight: Radius.circular(20), + ), + // Gradient from darker top to lighter bottom + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + AppTheme.navyBlue.withValues(alpha: 0.15), // Darker at top + AppTheme.navyBlue.withValues(alpha: 0.08), // Lighter at bottom + Colors.transparent, // Fade to transparent + ], + stops: const [0.0, 0.7, 1.0], + ), + // Subtle border at the top + border: Border( + top: BorderSide( + color: AppTheme.brightNavy.withValues(alpha: 0.3), + width: 1, + ), + ), + ), + child: Container( + padding: const EdgeInsets.fromLTRB(16, 14, 16, 8), + child: Row( + children: [ + _buildMiniAvatar(parentNode), + const SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Previous chain', + style: GoogleFonts.inter( + color: AppTheme.textSecondary.withValues(alpha: 0.8), + fontSize: 10, + fontWeight: FontWeight.w600, + letterSpacing: 0.5, + ), + ), + const SizedBox(height: 3), + Text( + parentNode.post.author?.displayName ?? 'Anonymous', + style: GoogleFonts.inter( + color: AppTheme.navyBlue.withValues(alpha: 0.9), + fontSize: 12, + fontWeight: FontWeight.w600, + ), + ), + const SizedBox(height: 2), + Text( + parentNode.post.body, + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: GoogleFonts.inter( + color: AppTheme.navyText.withValues(alpha: 0.75), + fontSize: 12, + height: 1.3, + ), + ), + ], + ), ), - boxShadow: [ - BoxShadow( - color: AppTheme.navyBlue.withValues(alpha: 0.06), - blurRadius: 16, - offset: const Offset(0, 6), + const SizedBox(width: 8), + Container( + padding: const EdgeInsets.all(6), + decoration: BoxDecoration( + color: AppTheme.brightNavy.withValues(alpha: 0.1), + borderRadius: BorderRadius.circular(8), ), - ], - ), - child: Row( - children: [ - _buildMiniAvatar(parentNode), - const SizedBox(width: 10), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Previous chain', - style: GoogleFonts.inter( - color: AppTheme.textSecondary, - fontSize: 11, - fontWeight: FontWeight.w600, - letterSpacing: 0.4, - ), - ), - const SizedBox(height: 4), - Text( - parentNode.post.author?.displayName ?? 'Anonymous', - style: GoogleFonts.inter( - color: AppTheme.navyBlue.withValues(alpha: 0.85), - fontSize: 12, - fontWeight: FontWeight.w600, - ), - ), - const SizedBox(height: 2), - Text( - parentNode.post.body, - maxLines: 2, - overflow: TextOverflow.ellipsis, - style: GoogleFonts.inter( - color: AppTheme.navyText.withValues(alpha: 0.7), - fontSize: 12, - height: 1.4, - ), - ), - ], - ), - ), - const SizedBox(width: 8), - Icon( + child: Icon( Icons.arrow_upward, - size: 18, - color: AppTheme.brightNavy, + size: 16, + color: AppTheme.brightNavy.withValues(alpha: 0.8), ), - ], - ), + ), + ], ), ), ), ), - ).animate().fadeIn(duration: 220.ms).slideY(begin: -0.1, end: 0); + ).animate().fadeIn(duration: 220.ms).slideY(begin: -0.08, end: 0); } Widget _buildMiniAvatar(ThreadNode node) { final avatarUrl = node.post.author?.avatarUrl; @@ -629,7 +643,7 @@ class _KineticThreadWidgetState extends ConsumerState return Hero( tag: 'thread_post_${node.post.id}', child: Container( - margin: const EdgeInsets.fromLTRB(16, 6, 16, 10), + margin: const EdgeInsets.fromLTRB(16, 0, 16, 10), decoration: BoxDecoration( color: AppTheme.cardSurface, borderRadius: BorderRadius.circular(20),