@@ -635,6 +635,167 @@ const Hooks = {
635635 } ) ;
636636 } ,
637637 } ,
638+ CompensationStrengthIndicator : {
639+ mounted ( ) {
640+ const input = this . el . querySelector ( "input[type='text']" ) ;
641+ const strengthBar = this . el . querySelector ( "[data-strength-bar]" ) ;
642+ const strengthLabel = this . el . querySelector ( "[data-strength-label]" ) ;
643+
644+ if ( ! input || ! strengthBar || ! strengthLabel ) return ;
645+
646+ const minAmount = 50000 ;
647+
648+ const expandShorthand = ( value : string ) : string => {
649+ const trimmed = value . trim ( ) . toLowerCase ( ) ;
650+
651+ // Handle 'k' for thousands (e.g., "100k" -> "100000")
652+ if ( trimmed . endsWith ( "k" ) ) {
653+ const number = parseFloat ( trimmed . slice ( 0 , - 1 ) ) ;
654+ if ( ! isNaN ( number ) ) {
655+ return Math . floor ( number * 1000 ) . toString ( ) ;
656+ }
657+ }
658+
659+ // Handle 'm' for millions (e.g., "1m" -> "1000000")
660+ if ( trimmed . endsWith ( "m" ) ) {
661+ const number = parseFloat ( trimmed . slice ( 0 , - 1 ) ) ;
662+ if ( ! isNaN ( number ) ) {
663+ return Math . floor ( number * 1000000 ) . toString ( ) ;
664+ }
665+ }
666+
667+ // Return just the digits if no shorthand
668+ return value . replace ( / [ ^ 0 - 9 ] / g, "" ) ;
669+ } ;
670+
671+ const formatWithCommas = ( value : string ) : string => {
672+ // First expand any shorthand notation
673+ const expanded = expandShorthand ( value ) ;
674+ // Add commas for thousands separators
675+ return expanded . replace ( / \B (? = ( \d { 3 } ) + (? ! \d ) ) / g, "," ) ;
676+ } ;
677+
678+ const updateStrength = ( ) => {
679+ const value = expandShorthand ( input . value ) ;
680+ const amount = parseInt ( value ) || 0 ;
681+
682+ let strength = 0 ;
683+ let label = "" ;
684+ let color = "bg-gray-200" ;
685+
686+ if ( amount >= 500000 ) {
687+ strength = 99 ;
688+ label = "Big D Energy" ;
689+ color = "bg-emerald-500" ;
690+ } else if ( amount >= 400000 ) {
691+ strength = 90 ;
692+ label = "Baller Status" ;
693+ color = "bg-emerald-500" ;
694+ } else if ( amount >= 300000 ) {
695+ strength = 80 ;
696+ label = "High Roller" ;
697+ color = "bg-emerald-500" ;
698+ } else if ( amount >= 200000 ) {
699+ strength = 70 ;
700+ label = "Big League" ;
701+ color = "bg-emerald-500" ;
702+ } else if ( amount >= 150000 ) {
703+ strength = 60 ;
704+ label = "Major League" ;
705+ color = "bg-emerald-500" ;
706+ } else if ( amount >= 100000 ) {
707+ strength = 50 ;
708+ label = "Six Figures" ;
709+ color = "bg-emerald-500" ;
710+ } else if ( amount >= 75000 ) {
711+ strength = 40 ;
712+ label = "Solid Pay" ;
713+ color = "bg-emerald-500" ;
714+ } else if ( amount >= minAmount ) {
715+ strength = 30 ;
716+ label = "Decent" ;
717+ color = "bg-emerald-500" ;
718+ }
719+
720+ // Update strength bar
721+ strengthBar . style . width = `${ strength } %` ;
722+ strengthBar . className = `h-2 rounded-full transition-all duration-300 ${ color } ` ;
723+
724+ // Show/hide the entire indicator section
725+ const indicatorSection = strengthBar . closest ( ".mt-2" ) ;
726+ if ( amount >= minAmount ) {
727+ indicatorSection . style . display = "block" ;
728+ } else {
729+ indicatorSection . style . display = "none" ;
730+ }
731+
732+ // Update label
733+ strengthLabel . textContent = label ;
734+ strengthLabel . className = `text-sm font-medium transition-colors duration-300 ${
735+ strength >= 80
736+ ? "text-emerald-500"
737+ : strength >= 60
738+ ? "text-emerald-500"
739+ : strength >= 40
740+ ? "text-emerald-500"
741+ : strength >= 20
742+ ? "text-emerald-500"
743+ : "text-gray-600"
744+ } `;
745+ } ;
746+
747+ const handleInput = ( e : Event ) => {
748+ const target = e . target as HTMLInputElement ;
749+ const cursorPosition = target . selectionStart || 0 ;
750+ const oldValue = target . value ;
751+
752+ // Check if user just typed 'k' or 'm' to trigger expansion
753+ const shouldExpand =
754+ oldValue . toLowerCase ( ) . endsWith ( "k" ) ||
755+ oldValue . toLowerCase ( ) . endsWith ( "m" ) ;
756+
757+ let formattedValue : string ;
758+ let newCursorPosition = cursorPosition ;
759+
760+ if ( shouldExpand ) {
761+ // Expand shorthand and format with commas
762+ formattedValue = formatWithCommas ( oldValue ) ;
763+ // Place cursor at the end after expansion
764+ newCursorPosition = formattedValue . length ;
765+ } else {
766+ // Just format with commas, preserving user input
767+ const digitsOnly = oldValue . replace ( / [ ^ 0 - 9 ] / g, "" ) ;
768+ formattedValue = digitsOnly . replace ( / \B (? = ( \d { 3 } ) + (? ! \d ) ) / g, "," ) ;
769+
770+ // Adjust cursor position to account for added/removed commas
771+ const oldCommas = ( oldValue . match ( / , / g) || [ ] ) . length ;
772+ const newCommas = ( formattedValue . match ( / , / g) || [ ] ) . length ;
773+ newCursorPosition = cursorPosition + ( newCommas - oldCommas ) ;
774+ }
775+
776+ // Only update if the value changed to prevent cursor jumping
777+ if ( oldValue !== formattedValue ) {
778+ target . value = formattedValue ;
779+
780+ // Set cursor position after the DOM updates
781+ setTimeout ( ( ) => {
782+ target . setSelectionRange ( newCursorPosition , newCursorPosition ) ;
783+ } , 0 ) ;
784+ }
785+
786+ updateStrength ( ) ;
787+ } ;
788+
789+ input . addEventListener ( "input" , handleInput ) ;
790+ input . addEventListener ( "keyup" , updateStrength ) ;
791+
792+ // Initial formatting and update
793+ if ( input . value ) {
794+ input . value = formatWithCommas ( input . value ) ;
795+ }
796+ updateStrength ( ) ;
797+ } ,
798+ } ,
638799} satisfies Record < string , Partial < ViewHook > & Record < string , unknown > > ;
639800
640801// Accessible focus handling
0 commit comments