@@ -18,6 +18,7 @@ import {HexagonConnection} from "./HexagonConnection";
18
18
import classNames from "classnames" ;
19
19
import { StyledSelect } from "../inputs/StyledSelect" ;
20
20
import { Label } from "reactstrap" ;
21
+ import { StyledCheckbox } from "../inputs/StyledCheckbox" ;
21
22
22
23
export type TierID = "subjects" | "fields" | "topics" ;
23
24
export interface Tier { id : TierID ; name : string ; for : string }
@@ -43,108 +44,30 @@ function naturalLanguageList(list: string[]) {
43
44
return `${ lowerCaseList . slice ( 0 , lastIndex ) . join ( ", " ) } and ${ lowerCaseList [ lastIndex ] } ` ;
44
45
}
45
46
46
- function hexRowTranslation ( deviceSize : DeviceSize , hexagon : HexagonProportions , i : number , questionFinderFilter : boolean ) {
47
- if ( i == 0 || ( deviceSize != "xs" && ! questionFinderFilter ) ) {
48
- return `translate(0,${ i * ( 6 * hexagon . quarterHeight + 2 * hexagon . padding ) } )` ;
49
- } else {
50
- const x = ( i * 2 - 1 ) * ( hexagon . halfWidth + hexagon . padding ) ;
51
- const y = 3 * hexagon . quarterHeight + hexagon . padding + ( hexagon . quarterHeight + hexagon . padding /* xs y diff */ ) ;
52
- return `translate(${ x } ,${ y } )` ;
53
- }
54
- }
55
-
56
- function connectionRowTranslation ( deviceSize : DeviceSize , hexagon : HexagonProportions , i : number , questionFinderFilter : boolean ) {
57
- if ( deviceSize != "xs" && ! questionFinderFilter ) {
58
- return `translate(${ hexagon . halfWidth + hexagon . padding } ,${ 3 * hexagon . quarterHeight + hexagon . padding + i * ( 6 * hexagon . quarterHeight + 2 * hexagon . padding ) } )` ;
59
- } else {
60
- return `translate(0,0)` ; // positioning is managed absolutely not through transformation
61
- }
62
- }
63
-
64
- function hexagonTranslation ( deviceSize : DeviceSize , hexagon : HexagonProportions , i : number , j : number , questionFinderFilter : boolean ) {
65
- if ( i == 0 || ( deviceSize != "xs" && ! questionFinderFilter ) ) {
66
- return `translate(${ j * 2 * ( hexagon . halfWidth + hexagon . padding ) } ,0)` ;
67
- } else {
68
- return `translate(0,${ j * ( 4 * hexagon . quarterHeight + hexagon . padding ) } )` ;
69
- }
70
- }
71
-
72
47
export function HierarchyFilterHexagonal ( { tiers, choices, selections, questionFinderFilter, setTierSelection} : HierarchyFilterProps ) {
73
- const deviceSize = useDeviceSize ( ) ;
74
- const leadingHexagon = calculateHexagonProportions ( 36 , deviceSize === "xs" ? 2 : 8 ) ;
75
- const hexagon = calculateHexagonProportions ( 36 , deviceSize === "xs" || ! ! questionFinderFilter ? 16 : 8 ) ;
76
- const focusPadding = 3 ;
77
-
78
- const maxOptions = choices . slice ( 1 ) . map ( c => c . length ) . reduce ( ( a , b ) => Math . max ( a , b ) , 0 ) ;
79
- const height = ( deviceSize != "xs" && ! questionFinderFilter ) ?
80
- 2 * focusPadding + 4 * hexagon . quarterHeight + ( tiers . length - 1 ) * ( 6 * hexagon . quarterHeight + 2 * hexagon . padding ) :
81
- 2 * focusPadding + 4 * hexagon . quarterHeight + maxOptions * ( 4 * hexagon . quarterHeight + hexagon . padding ) + ( maxOptions ? hexagon . padding : 0 ) ;
82
- const width = ( 8 * leadingHexagon . halfWidth ) + ( 6 * leadingHexagon . padding ) + ( 2 * focusPadding ) ;
83
-
84
- return < svg
85
- viewBox = { questionFinderFilter ? `0 0 ${ width } ${ height } ` : "" }
86
- width = { questionFinderFilter ? "auto" : "100%" }
87
- className = { classNames ( { "mx-auto d-block" : questionFinderFilter } ) }
88
- height = { `${ height } px` }
89
- >
90
- < title > Topic filter selector</ title >
91
- < g id = "hexagonal-filter" transform = { `translate(${ focusPadding } ,${ focusPadding } )` } >
92
- { /* Connections */ }
93
- { tiers . slice ( 1 ) . map ( ( tier , i ) => {
94
- const subject = selections ?. [ 0 ] ?. [ 0 ] ? selections [ 0 ] [ 0 ] . value : "" ;
95
- return < g key = { tier . for } transform = { connectionRowTranslation ( deviceSize , hexagon , i , ! ! questionFinderFilter ) } >
96
- < HexagonConnection
97
- sourceIndex = { choices [ i ] . map ( c => c . value ) . indexOf ( selections [ i ] [ 0 ] ?. value ) }
98
- optionIndices = { [ ...choices [ i + 1 ] . keys ( ) ] } // range from 0 to choices[i+1].length
99
- targetIndices = { selections [ i + 1 ] ?. map ( s => choices [ i + 1 ] . map ( c => c . value ) . indexOf ( s . value ) ) || [ - 1 ] }
100
- leadingHexagonProportions = { leadingHexagon } hexagonProportions = { hexagon } connectionProperties = { connectionProperties }
101
- rowIndex = { i } mobile = { deviceSize === "xs" || ! ! questionFinderFilter } className = { `connection ${ subject } ` }
48
+ return < div >
49
+ { tiers . map ( ( tier , i ) => ( // Subject / Field / Topic
50
+ choices [ i ] . map ( ( choice , j ) => {
51
+ const isSelected = ! ! selections [ i ] ?. map ( s => s . value ) . includes ( choice . value ) ;
52
+ function selectValue ( ) {
53
+ setTierSelection ( i ) ( isSelected ?
54
+ selections [ i ] . filter ( s => s . value !== choice . value ) : // remove
55
+ [ ...( selections [ i ] || [ ] ) , choice ] // add
56
+ ) ;
57
+ }
58
+
59
+ return < div key = { choice . value } className = "ps-3 ms-2" >
60
+ < StyledCheckbox
61
+ color = "primary"
62
+ checked = { isSelected }
63
+ onChange = { selectValue }
64
+ label = { < span > { choice . label } </ span > }
65
+ className = "ps-3"
102
66
/>
103
- </ g > ;
104
- } ) }
105
-
106
- { /* Hexagons */ }
107
- { tiers . map ( ( tier , i ) => < g key = { tier . for } transform = { hexRowTranslation ( deviceSize , hexagon , i , ! ! questionFinderFilter ) } >
108
- { choices [ i ] . map ( ( choice , j ) => {
109
- const subject = i == 0 ? choice . value : selections [ 0 ] [ 0 ] . value ;
110
- const isSelected = ! ! selections [ i ] ?. map ( s => s . value ) . includes ( choice . value ) ;
111
- const longWordInLabel = choice . label . split ( / \s / ) . some ( word => word . length > 10 ) ;
112
- const tag = tags . getById ( choice . value ) ;
113
- const isComingSoon = isDefined ( tag . comingSoonDate ) ;
114
- function selectValue ( ) {
115
- setTierSelection ( i ) ( isSelected ?
116
- selections [ i ] . filter ( s => s . value !== choice . value ) : // remove
117
- [ ...( selections [ i ] || [ ] ) , choice ] // add
118
- ) ;
119
- }
120
-
121
- return < g key = { choice . value } transform = { hexagonTranslation ( deviceSize , i === 0 ? leadingHexagon : hexagon , i , j , ! ! questionFinderFilter ) } >
122
- < Hexagon { ...hexagon } className = { classNames ( "hex" , subject , { "active" : isSelected && ! isComingSoon , "de-emph" : isComingSoon } ) } />
123
- < foreignObject width = { hexagon . halfWidth * 2 } height = { hexagon . quarterHeight * 4 } >
124
- < div className = { classNames ( "hexagon-tier-title" , { "active" : isSelected && ! isComingSoon , "de-emph" : isComingSoon , "small" : longWordInLabel } ) } >
125
- { choice . label }
126
- </ div >
127
- { tag . comingSoonDate && < div className = { classNames ( subject , "hexagon-coming-soon" ) } >
128
- Coming { tag . comingSoonDate }
129
- </ div > }
130
- </ foreignObject >
131
-
132
- < Hexagon
133
- { ...hexagon } className = { classNames ( "hex none" , { "clickable" : ! isComingSoon } ) } properties = { { clickable : ! isComingSoon } } role = "button"
134
- tabIndex = { isComingSoon ? - 1 : 0 } onClick = { isComingSoon ? noop : selectValue } onKeyPress = { isComingSoon ? noop : ifKeyIsEnter ( selectValue ) }
135
- >
136
- { ! isComingSoon && < title >
137
- { `${ isSelected ? "Remove" : "Add" } the ${ tier . name . toLowerCase ( ) } "${ choice . label } " ${ isSelected ? "from" : "to" } your ${ siteSpecific ( "gameboard" , "quiz" ) } filter` }
138
- </ title > }
139
- </ Hexagon >
140
- { isComingSoon && < title >
141
- This topic is coming soon
142
- </ title > }
143
- </ g > ;
144
- } ) }
145
- </ g > ) }
146
- </ g >
147
- </ svg > ;
67
+ </ div > ;
68
+ } )
69
+ ) ) }
70
+ </ div > ;
148
71
}
149
72
150
73
export function HierarchyFilterSummary ( { tiers, choices, selections} : HierarchySummaryProps ) {
0 commit comments