Skip to content

Commit 386b7d4

Browse files
fix(WeightedAssessmentSurvey): Add help text functionality for questions
- Introduced an optional `helpText` field in the `Question` interface to provide additional information via tooltips. - Implemented a help text editor in edit mode, allowing users to input help text for each question. - Enhanced the UI to display a help icon next to question text, showing the help text on hover. - Updated CSS for help text and icons to improve layout and user experience.
1 parent bb541ec commit 386b7d4

3 files changed

Lines changed: 170 additions & 41 deletions

File tree

js/src/components/widgets/WeightedAssessmentSurveyWidget.tsx

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ interface Question {
1717
timestamps: Record<string, number>; // Use string keys (created, modified)
1818
doNotKnow?: boolean; // Flag to indicate "I do not know" response
1919
antiText?: string; // Add optional anti-text field
20+
helpText?: string; // Add optional help text field for info icon tooltip
2021
}
2122

2223
interface Category {
@@ -2074,6 +2075,13 @@ const WeightedAssessmentSurveyWidget: React.FC<WeightedAssessmentSurveyWidgetPro
20742075
setSurveyData(newData);
20752076
};
20762077

2078+
// Add function to update question help text in edit mode
2079+
const updateQuestionHelpText = (groupIndex: number, questionIndex: number, helpText: string) => {
2080+
const newData = { ...surveyData };
2081+
newData.groups[groupIndex].questions[questionIndex].helpText = helpText;
2082+
setSurveyData(newData);
2083+
};
2084+
20772085
return (
20782086
<div className={`weighted-assessment-survey ${props.class_name || ''} ${readOnly ? 'read-only' : ''}`}>
20792087
<div className="progress-indicator">
@@ -2512,12 +2520,39 @@ const WeightedAssessmentSurveyWidget: React.FC<WeightedAssessmentSurveyWidgetPro
25122520
) : (
25132521
<div className="question-content">
25142522
<div className="question-text-container">
2515-
<SimpleMarkdownRender content={question.text} className="question-text" />
2523+
<div className="question-text-with-help">
2524+
<SimpleMarkdownRender
2525+
content={question.text}
2526+
className="question-text-inline"
2527+
/>
2528+
{question.helpText && (
2529+
<span className="question-help-icon" title={question.helpText}>
2530+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2531+
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 17h-2v-2h2v2zm2.07-7.75l-.9.92C13.45 12.9 13 13.5 13 15h-2v-.5c0-1.1.45-2.1 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41 0-1.1-.9-2-2-2s-2 .9-2 2H8c0-2.21 1.79-4 4-4s4 1.79 4 4c0 .88-.36 1.68-.93 2.25z" fill="currentColor"/>
2532+
</svg>
2533+
</span>
2534+
)}
2535+
</div>
25162536
</div>
25172537
</div>
25182538
)}
25192539

2520-
{/* Add anti-text input in edit mode */}
2540+
{/* Add help text editor in edit mode */}
2541+
{editMode && (
2542+
<div className="help-text-container">
2543+
<label className="help-text-label">
2544+
Question Help Text (shown on hover):
2545+
<textarea
2546+
className="textarea-input help-text-input"
2547+
value={question.helpText || ""}
2548+
onChange={(e) => updateQuestionHelpText(groupIndex, questionIndex, e.target.value)}
2549+
placeholder="Enter optional help text for this question..."
2550+
/>
2551+
</label>
2552+
</div>
2553+
)}
2554+
2555+
{/* Anti-text input in edit mode */}
25212556
{editMode && (
25222557
<div className="anti-text-container">
25232558
<label className="anti-text-label">Anti-Question Text:</label>
@@ -2545,11 +2580,21 @@ const WeightedAssessmentSurveyWidget: React.FC<WeightedAssessmentSurveyWidgetPro
25452580
}
25462581
min={question.min}
25472582
max={question.max}
2548-
onChange={(e) => handleSliderDrag(groupIndex, questionIndex, Number(e.target.value))}
2583+
onChange={(e) => {
2584+
const newValue = Number(e.target.value);
2585+
handleSliderDrag(groupIndex, questionIndex, newValue);
2586+
// Also update the value immediately to prevent Chrome issues
2587+
updateQuestionValue(groupIndex, questionIndex, newValue);
2588+
}}
25492589
onMouseMove={(e) => handleSliderMouseMove(e, groupIndex, questionIndex, question)}
25502590
onMouseLeave={handleSliderMouseLeave}
25512591
onMouseUp={handleSliderRelease}
25522592
onTouchEnd={handleSliderRelease}
2593+
onClick={(e) => {
2594+
// Ensure the value is updated on direct click
2595+
const newValue = Number((e.target as HTMLInputElement).value);
2596+
updateQuestionValue(groupIndex, questionIndex, newValue);
2597+
}}
25532598
disabled={readOnly}
25542599
/>
25552600
<div className="slider-markers">

js/src/css/components/WeightedAssessmentSurvey.scss

Lines changed: 121 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -419,12 +419,27 @@
419419
justify-content: space-between;
420420
}
421421

422-
.question-text {
423-
font-size: 16px;
424-
font-weight: 500;
425-
line-height: 1.4;
426-
margin-bottom: 16px;
422+
.question-text-container {
423+
width: 100%;
424+
min-height: 24px;
425+
margin-bottom: 12px;
426+
position: relative;
427+
}
428+
429+
.question-text-with-help {
430+
display: inline-flex;
431+
align-items: center;
432+
flex-wrap: wrap;
433+
gap: 4px;
434+
}
435+
436+
.question-text-inline {
437+
font-size: 1rem;
438+
font-weight: 400;
427439
color: var(--ui-widget-primary-text);
440+
line-height: 1.5;
441+
margin: 0;
442+
display: inline;
428443
}
429444

430445
.question-controls {
@@ -657,38 +672,48 @@
657672
.assessment-slider {
658673
-webkit-appearance: none;
659674
width: 100%;
660-
height: 4px;
661-
border-radius: 2px;
675+
height: 8px; /* Increased from 4px for better touch target */
676+
border-radius: 4px;
662677
background: #e0e0e0;
663678
outline: none;
664679
position: relative;
665680
cursor: pointer;
666681
transition: background 0.2s ease;
667682
z-index: 2;
683+
margin: 8px 0; /* Add margin to increase click target area */
684+
padding: 0; /* Reset padding */
668685
}
669686

670-
/* Hide the thumb for unselected sliders */
687+
/* Make the thumb always visible but smaller for unselected sliders */
671688
.assessment-slider.unselected::-webkit-slider-thumb {
672689
-webkit-appearance: none;
673690
appearance: none;
674-
width: 0;
675-
height: 0;
676-
opacity: 0;
691+
width: 12px;
692+
height: 12px;
693+
border-radius: 50%;
694+
background: rgba(var(--ui-widget-primary-background-rgb), 0.9);
695+
border: 1px solid rgba(var(--ui-widget-focus-border-rgb), 0.5);
696+
cursor: pointer;
697+
opacity: 0.7;
677698
transition: opacity 0.25s ease-out, width 0.25s ease-out, height 0.25s ease-out, transform 0.25s ease-out;
678699
}
679700

680701
.assessment-slider.unselected::-moz-range-thumb {
681-
width: 0;
682-
height: 0;
683-
opacity: 0;
702+
width: 12px;
703+
height: 12px;
704+
border-radius: 50%;
705+
background: rgba(var(--ui-widget-primary-background-rgb), 0.9);
706+
border: 1px solid rgba(var(--ui-widget-focus-border-rgb), 0.5);
707+
cursor: pointer;
708+
opacity: 0.7;
684709
transition: opacity 0.25s ease-out, width 0.25s ease-out, height 0.25s ease-out, transform 0.25s ease-out;
685710
}
686711

687-
/* Show a hover indicator on unselected sliders */
712+
/* Show a more prominent hover indicator on unselected sliders */
688713
.assessment-slider.unselected:hover::-webkit-slider-thumb {
689714
width: 16px;
690715
height: 16px;
691-
opacity: 0.9;
716+
opacity: 1;
692717
border: 2px solid rgba(var(--ui-widget-focus-border-rgb), 0.8);
693718
background: rgba(var(--ui-widget-primary-background-rgb), 1);
694719
box-shadow: 0 0 8px rgba(0, 0, 0, 0.15);
@@ -699,7 +724,7 @@
699724
.assessment-slider.unselected:hover::-moz-range-thumb {
700725
width: 16px;
701726
height: 16px;
702-
opacity: 0.9;
727+
opacity: 1;
703728
border: 2px solid rgba(var(--ui-widget-focus-border-rgb), 0.8);
704729
background: rgba(var(--ui-widget-primary-background-rgb), 1);
705730
box-shadow: 0 0 8px rgba(0, 0, 0, 0.15);
@@ -711,20 +736,21 @@
711736
.assessment-slider::-webkit-slider-thumb {
712737
-webkit-appearance: none;
713738
appearance: none;
714-
width: 16px;
715-
height: 16px;
739+
width: 18px; /* Slightly larger */
740+
height: 18px; /* Slightly larger */
716741
border-radius: 50%;
717742
background: var(--ui-widget-primary-background);
718743
border: 2px solid var(--ui-widget-focus-border);
719744
cursor: pointer;
720745
transition: transform 0.1s;
721746
position: relative;
722747
z-index: 3;
748+
margin-top: -5px; /* Helps with vertical alignment */
723749
}
724750

725751
.assessment-slider::-moz-range-thumb {
726-
width: 16px;
727-
height: 16px;
752+
width: 18px; /* Slightly larger */
753+
height: 18px; /* Slightly larger */
728754
border-radius: 50%;
729755
background: var(--ui-widget-primary-background);
730756
border: 2px solid var(--ui-widget-focus-border);
@@ -1390,23 +1416,6 @@
13901416
width: 100%;
13911417
}
13921418

1393-
.question-text-container {
1394-
width: 100%;
1395-
min-height: 24px;
1396-
margin-bottom: 12px;
1397-
}
1398-
1399-
.question-text {
1400-
font-size: 1rem;
1401-
font-weight: 400;
1402-
color: var(--ui-widget-primary-text);
1403-
line-height: 1.5;
1404-
margin: 0;
1405-
white-space: normal;
1406-
overflow: visible;
1407-
text-overflow: clip;
1408-
}
1409-
14101419
.controls-row {
14111420
display: flex;
14121421
align-items: center;
@@ -2410,3 +2419,77 @@
24102419
font-size: 14px;
24112420
line-height: normal; /* Ensure standard line height */
24122421
}
2422+
2423+
/* Question help icon styling */
2424+
.question-help-icon {
2425+
display: inline-flex;
2426+
align-items: center;
2427+
justify-content: center;
2428+
color: #6b7280;
2429+
transition: color 0.2s;
2430+
width: 18px;
2431+
height: 18px;
2432+
cursor: help;
2433+
margin-left: 2px;
2434+
position: relative;
2435+
}
2436+
2437+
.question-help-icon:hover {
2438+
color: var(--ui-widget-focus-border);
2439+
}
2440+
2441+
/* Add tooltip functionality */
2442+
.question-help-icon[title]:hover::after {
2443+
content: attr(title);
2444+
position: absolute;
2445+
left: 50%;
2446+
transform: translateX(-50%);
2447+
bottom: calc(100% + 5px);
2448+
background: rgba(0, 0, 0, 0.8);
2449+
color: white;
2450+
padding: 8px 12px;
2451+
border-radius: 4px;
2452+
font-size: 0.85rem;
2453+
max-width: 250px;
2454+
width: max-content;
2455+
z-index: 100;
2456+
text-align: left;
2457+
pointer-events: none;
2458+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
2459+
white-space: normal;
2460+
word-break: break-word;
2461+
}
2462+
2463+
.question-help-icon[title]:hover::before {
2464+
content: '';
2465+
position: absolute;
2466+
left: 50%;
2467+
transform: translateX(-50%);
2468+
bottom: calc(100% + 0px);
2469+
border-left: 5px solid transparent;
2470+
border-right: 5px solid transparent;
2471+
border-top: 5px solid rgba(0, 0, 0, 0.8);
2472+
z-index: 100;
2473+
pointer-events: none;
2474+
}
2475+
2476+
/* Help text editor in edit mode */
2477+
.help-text-container {
2478+
margin-top: 8px;
2479+
margin-bottom: 12px;
2480+
}
2481+
2482+
.help-text-label {
2483+
display: block;
2484+
font-size: 0.85rem;
2485+
color: var(--ui-widget-secondary-text);
2486+
margin-bottom: 4px;
2487+
}
2488+
2489+
.help-text-input {
2490+
width: 100%;
2491+
min-height: 60px;
2492+
padding: 8px;
2493+
margin-top: 4px;
2494+
font-size: 0.9rem;
2495+
}

python/src/numerous/widgets/advanced/weighted_assessment_survey.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class Question(TypedDict):
3737
timestamps: dict[str, float] # Using dict for created/modified
3838
doNotKnow: NotRequired[bool]
3939
antiText: NotRequired[str]
40+
helpText: NotRequired[str] # Add helpText for question info/tooltip
4041

4142

4243
class Category(TypedDict):

0 commit comments

Comments
 (0)