@bloom-housing/ui-components 2.0.0-pre-tailwind

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (223) hide show
  1. package/.jest/setup-tests.js +24 -0
  2. package/CHANGELOG.md +20 -0
  3. package/README.md +195 -0
  4. package/index.ts +148 -0
  5. package/jest.config.js +41 -0
  6. package/package.json +98 -0
  7. package/public/images/alameda-logo-white.svg +1 -0
  8. package/public/images/arrow-down.png +0 -0
  9. package/public/images/arrow-down.svg +1 -0
  10. package/public/images/check.png +0 -0
  11. package/public/images/check.svg +11 -0
  12. package/public/images/eho-logo-white.svg +1 -0
  13. package/public/images/eho-logo.svg +1 -0
  14. package/public/images/logo_glyph.svg +11 -0
  15. package/src/actions/Button.scss +157 -0
  16. package/src/actions/Button.tsx +80 -0
  17. package/src/actions/ExpandableContent.tsx +29 -0
  18. package/src/actions/ExpandableText.scss +18 -0
  19. package/src/actions/ExpandableText.tsx +52 -0
  20. package/src/actions/LinkButton.tsx +30 -0
  21. package/src/actions/LocalizedLink.tsx +11 -0
  22. package/src/authentication/AuthContext.ts +327 -0
  23. package/src/authentication/RequireLogin.tsx +62 -0
  24. package/src/authentication/index.ts +5 -0
  25. package/src/authentication/timeout.tsx +127 -0
  26. package/src/authentication/token.ts +17 -0
  27. package/src/authentication/useRequireLoggedInUser.ts +19 -0
  28. package/src/blocks/ActionBlock.scss +108 -0
  29. package/src/blocks/ActionBlock.tsx +51 -0
  30. package/src/blocks/AppStatusItem.scss +140 -0
  31. package/src/blocks/AppStatusItem.tsx +75 -0
  32. package/src/blocks/DashBlock.tsx +42 -0
  33. package/src/blocks/DashBlocks.scss +56 -0
  34. package/src/blocks/DashBlocks.tsx +7 -0
  35. package/src/blocks/FormCard.scss +201 -0
  36. package/src/blocks/FormCard.tsx +29 -0
  37. package/src/blocks/HousingCounselor.tsx +51 -0
  38. package/src/blocks/ImageCard.scss +91 -0
  39. package/src/blocks/ImageCard.tsx +77 -0
  40. package/src/blocks/InfoCard.scss +42 -0
  41. package/src/blocks/InfoCard.tsx +44 -0
  42. package/src/blocks/StatusBar.scss +30 -0
  43. package/src/blocks/StatusBar.tsx +31 -0
  44. package/src/blocks/ViewItem.scss +59 -0
  45. package/src/blocks/ViewItem.tsx +32 -0
  46. package/src/config/ConfigContext.tsx +36 -0
  47. package/src/config/NavigationContext.tsx +54 -0
  48. package/src/config/index.ts +2 -0
  49. package/src/footers/ExygyFooter.tsx +12 -0
  50. package/src/footers/SiteFooter.scss +28 -0
  51. package/src/footers/SiteFooter.tsx +10 -0
  52. package/src/forms/CloudinaryUpload.ts +50 -0
  53. package/src/forms/DOBField.tsx +132 -0
  54. package/src/forms/DateField.tsx +120 -0
  55. package/src/forms/Dropzone.scss +17 -0
  56. package/src/forms/Dropzone.tsx +67 -0
  57. package/src/forms/Field.tsx +115 -0
  58. package/src/forms/FieldGroup.tsx +82 -0
  59. package/src/forms/Form.tsx +22 -0
  60. package/src/forms/HouseholdMemberForm.tsx +41 -0
  61. package/src/forms/HouseholdSizeField.tsx +74 -0
  62. package/src/forms/PhoneField.tsx +69 -0
  63. package/src/forms/PhoneMask.tsx +24 -0
  64. package/src/forms/Select.tsx +80 -0
  65. package/src/forms/Textarea.scss +40 -0
  66. package/src/forms/Textarea.tsx +64 -0
  67. package/src/forms/TimeField.tsx +176 -0
  68. package/src/global/AppearanceTypes.ts +46 -0
  69. package/src/global/ApplicationStatusType.ts +6 -0
  70. package/src/global/accordion.scss +4 -0
  71. package/src/global/blocks.scss +137 -0
  72. package/src/global/custom_counter.scss +50 -0
  73. package/src/global/forms.scss +362 -0
  74. package/src/global/headers.scss +89 -0
  75. package/src/global/homepage.scss +8 -0
  76. package/src/global/index.scss +72 -0
  77. package/src/global/lists.scss +21 -0
  78. package/src/global/markdown.scss +33 -0
  79. package/src/global/mixins.scss +175 -0
  80. package/src/global/navbar.scss +280 -0
  81. package/src/global/print.scss +59 -0
  82. package/src/global/tables.scss +197 -0
  83. package/src/global/text.scss +141 -0
  84. package/src/global/vendor/AgPagination.tsx +133 -0
  85. package/src/global/vendor/_setup_bulma.scss +31 -0
  86. package/src/global/vendor/ag_grid.scss +140 -0
  87. package/src/headers/Hero.scss +56 -0
  88. package/src/headers/Hero.tsx +76 -0
  89. package/src/headers/PageHeader.scss +31 -0
  90. package/src/headers/PageHeader.tsx +39 -0
  91. package/src/headers/SiteHeader.tsx +136 -0
  92. package/src/helpers/address.tsx +46 -0
  93. package/src/helpers/blankApplication.ts +108 -0
  94. package/src/helpers/capitalize.tsx +7 -0
  95. package/src/helpers/dateToString.ts +11 -0
  96. package/src/helpers/debounce.ts +12 -0
  97. package/src/helpers/formOptions.tsx +229 -0
  98. package/src/helpers/formatYesNoLabel.ts +9 -0
  99. package/src/helpers/getTranslationWithArguments.ts +14 -0
  100. package/src/helpers/links.ts +7 -0
  101. package/src/helpers/localeRoute.tsx +13 -0
  102. package/src/helpers/mergeDeep.ts +12 -0
  103. package/src/helpers/nextjs.ts +7 -0
  104. package/src/helpers/numberOrdinal.ts +17 -0
  105. package/src/helpers/occupancyFormatting.tsx +46 -0
  106. package/src/helpers/pdfs.ts +19 -0
  107. package/src/helpers/photos.ts +19 -0
  108. package/src/helpers/preferences.tsx +426 -0
  109. package/src/helpers/resolveObject.ts +5 -0
  110. package/src/helpers/state.tsx +7 -0
  111. package/src/helpers/tableSummaries.tsx +80 -0
  112. package/src/helpers/translator.tsx +37 -0
  113. package/src/helpers/useKeyPress.ts +17 -0
  114. package/src/helpers/useMutate.ts +40 -0
  115. package/src/helpers/useOutsideClick.ts +25 -0
  116. package/src/helpers/validators.ts +3 -0
  117. package/src/icons/HeaderBadge.scss +29 -0
  118. package/src/icons/HeaderBadge.tsx +38 -0
  119. package/src/icons/Icon.scss +76 -0
  120. package/src/icons/Icon.tsx +145 -0
  121. package/src/icons/Icons.tsx +556 -0
  122. package/src/lists/PreferencesList.scss +72 -0
  123. package/src/lists/PreferencesList.tsx +60 -0
  124. package/src/locales/es.json +745 -0
  125. package/src/locales/general.json +1307 -0
  126. package/src/locales/general_OLD.json +868 -0
  127. package/src/locales/vi.json +745 -0
  128. package/src/locales/zh.json +745 -0
  129. package/src/navigation/Breadcrumbs.scss +25 -0
  130. package/src/navigation/Breadcrumbs.tsx +27 -0
  131. package/src/navigation/FooterNav.scss +47 -0
  132. package/src/navigation/FooterNav.tsx +19 -0
  133. package/src/navigation/LanguageNav.scss +32 -0
  134. package/src/navigation/LanguageNav.tsx +53 -0
  135. package/src/navigation/ProgressNav.scss +102 -0
  136. package/src/navigation/ProgressNav.tsx +50 -0
  137. package/src/navigation/TabNav.scss +38 -0
  138. package/src/navigation/TabNav.tsx +69 -0
  139. package/src/navigation/Tabs.scss +65 -0
  140. package/src/navigation/Tabs.tsx +93 -0
  141. package/src/navigation/UserNav.tsx +37 -0
  142. package/src/notifications/AlertBox.scss +78 -0
  143. package/src/notifications/AlertBox.tsx +79 -0
  144. package/src/notifications/AlertNotice.scss +58 -0
  145. package/src/notifications/AlertNotice.tsx +37 -0
  146. package/src/notifications/ApplicationStatus.scss +10 -0
  147. package/src/notifications/ApplicationStatus.tsx +64 -0
  148. package/src/notifications/ErrorMessage.tsx +15 -0
  149. package/src/notifications/SiteAlert.tsx +54 -0
  150. package/src/notifications/StatusAside.scss +11 -0
  151. package/src/notifications/StatusAside.tsx +25 -0
  152. package/src/notifications/StatusMessage.scss +25 -0
  153. package/src/notifications/StatusMessage.tsx +59 -0
  154. package/src/notifications/alertTypes.ts +7 -0
  155. package/src/notifications/index.ts +4 -0
  156. package/src/overlays/Drawer.scss +105 -0
  157. package/src/overlays/Drawer.tsx +51 -0
  158. package/src/overlays/LoadingOverlay.scss +25 -0
  159. package/src/overlays/LoadingOverlay.tsx +29 -0
  160. package/src/overlays/Modal.scss +55 -0
  161. package/src/overlays/Modal.tsx +61 -0
  162. package/src/overlays/Overlay.scss +50 -0
  163. package/src/overlays/Overlay.tsx +100 -0
  164. package/src/page_components/listing/AdditionalFees.tsx +56 -0
  165. package/src/page_components/listing/ListingCard.scss +47 -0
  166. package/src/page_components/listing/ListingCard.tsx +34 -0
  167. package/src/page_components/listing/ListingDetailHeader.tsx +25 -0
  168. package/src/page_components/listing/ListingDetails.tsx +29 -0
  169. package/src/page_components/listing/ListingMap.scss +36 -0
  170. package/src/page_components/listing/ListingMap.tsx +138 -0
  171. package/src/page_components/listing/ListingsGroup.scss +65 -0
  172. package/src/page_components/listing/ListingsGroup.tsx +49 -0
  173. package/src/page_components/listing/UnitTables.tsx +111 -0
  174. package/src/page_components/listing/listing_sidebar/ApplicationSection.tsx +49 -0
  175. package/src/page_components/listing/listing_sidebar/Apply.tsx +225 -0
  176. package/src/page_components/listing/listing_sidebar/LeasingAgent.tsx +77 -0
  177. package/src/page_components/listing/listing_sidebar/ListingUpdated.tsx +20 -0
  178. package/src/page_components/listing/listing_sidebar/ReferralApplication.tsx +28 -0
  179. package/src/page_components/listing/listing_sidebar/SidebarAddress.tsx +56 -0
  180. package/src/page_components/listing/listing_sidebar/Waitlist.tsx +94 -0
  181. package/src/page_components/listing/listing_sidebar/WhatToExpect.tsx +22 -0
  182. package/src/page_components/listing/listing_sidebar/events/DownloadLotteryResults.tsx +34 -0
  183. package/src/page_components/listing/listing_sidebar/events/EventDateSection.tsx +24 -0
  184. package/src/page_components/listing/listing_sidebar/events/LotteryResultsEvent.tsx +26 -0
  185. package/src/page_components/listing/listing_sidebar/events/OpenHouseEvent.tsx +27 -0
  186. package/src/page_components/listing/listing_sidebar/events/PublicLotteryEvent.tsx +22 -0
  187. package/src/prototypes/AppCard.scss +64 -0
  188. package/src/prototypes/Back.scss +19 -0
  189. package/src/prototypes/ButtonGroup.scss +6 -0
  190. package/src/prototypes/ButtonPager.scss +22 -0
  191. package/src/prototypes/FieldSection.scss +35 -0
  192. package/src/prototypes/FieldSection.tsx +31 -0
  193. package/src/prototypes/GridItem.tsx +15 -0
  194. package/src/prototypes/SideNav.scss +32 -0
  195. package/src/prototypes/SideNav.tsx +14 -0
  196. package/src/prototypes/SummaryCard.scss +34 -0
  197. package/src/sections/ContentSection.scss +15 -0
  198. package/src/sections/ContentSection.tsx +25 -0
  199. package/src/sections/FooterSection.scss +6 -0
  200. package/src/sections/FooterSection.tsx +16 -0
  201. package/src/sections/GridSection.scss +72 -0
  202. package/src/sections/GridSection.tsx +82 -0
  203. package/src/sections/InfoCardGrid.scss +45 -0
  204. package/src/sections/InfoCardGrid.tsx +20 -0
  205. package/src/sections/ListSection.scss +7 -0
  206. package/src/sections/ListSection.tsx +23 -0
  207. package/src/sections/MarkdownSection.scss +13 -0
  208. package/src/sections/MarkdownSection.tsx +21 -0
  209. package/src/sections/ResponsiveContentList.tsx +67 -0
  210. package/src/sections/ResponsiveWrappers.tsx +23 -0
  211. package/src/tables/GroupedTable.tsx +86 -0
  212. package/src/tables/MinimalTable.tsx +32 -0
  213. package/src/tables/ResponsiveTable.tsx +24 -0
  214. package/src/tables/StandardTable.tsx +229 -0
  215. package/src/text/Description.scss +52 -0
  216. package/src/text/Description.tsx +24 -0
  217. package/src/text/Message.scss +16 -0
  218. package/src/text/Message.tsx +16 -0
  219. package/src/text/Tag.scss +94 -0
  220. package/src/text/Tag.tsx +22 -0
  221. package/tailwind.config.js +128 -0
  222. package/tailwind.tosass.js +29 -0
  223. package/tsconfig.json +31 -0
@@ -0,0 +1,31 @@
1
+ // Set up Bulma-specific variables and mixins
2
+ $white: $tailwind-white;
3
+ $background: #eee;
4
+ $link: $tailwind-primary;
5
+ $grey-dark: $link;
6
+ $white-bis: #eee;
7
+ $black: $tailwind-black;
8
+ $text: $black;
9
+ $border: 2px solid #ccc; // not sure how this gets used -JW
10
+ $radius-large: 8px;
11
+ $radius: 4px;
12
+ $desktop: $tailwind-screens-md;
13
+ $speed: 86ms;
14
+ $easing: ease-out;
15
+
16
+ $scheme-main: $white;
17
+ $scheme-main-bis: $white-bis;
18
+ $scheme-invert: $black;
19
+ $colors: (
20
+ "white": (
21
+ $white,
22
+ $black,
23
+ ),
24
+ "black": (
25
+ $black,
26
+ $white,
27
+ ),
28
+ );
29
+
30
+ @import "~bulma/sass/utilities/functions.sass";
31
+ @import "~bulma/sass/utilities/mixins.sass";
@@ -0,0 +1,140 @@
1
+ // AG Grid
2
+ @import "~ag-grid-community/src/styles/ag-grid.scss";
3
+ @import "~ag-grid-community/src/styles/ag-theme-alpine/sass/ag-theme-alpine-mixin";
4
+
5
+ .ag-theme-alpine.ag-theme-bloom {
6
+ // would like to remove the local theme class
7
+ @include ag-theme-alpine(
8
+ (
9
+ header-height: 83px,
10
+ row-height: 58px,
11
+ )
12
+ );
13
+
14
+ .ag-row {
15
+ height: ag-param(row-height);
16
+ }
17
+
18
+ .ag-header {
19
+ @apply whitespace-normal;
20
+ text-overflow: unset;
21
+ }
22
+
23
+ .ag-header-select-all {
24
+ margin: 0 0 0 18px;
25
+ }
26
+
27
+ .ag-header-cell {
28
+ @apply px-0;
29
+ }
30
+
31
+ .ag-cell-label-container {
32
+ @apply px-4;
33
+ }
34
+
35
+ .ag-header-cell-sorted-asc,
36
+ .ag-header-cell-sorted-desc {
37
+ box-shadow: inset 0px -3px 0px 0px $tailwind-primary;
38
+ }
39
+
40
+ .ag-header-icon .ag-icon.ag-icon-none {
41
+ @apply text-gray-600;
42
+ }
43
+
44
+ .ag-header-cell-text {
45
+ @apply whitespace-normal;
46
+ text-overflow: unset;
47
+ }
48
+
49
+ .ag-header-cell-text {
50
+ @apply uppercase;
51
+ @apply font-sans;
52
+ @apply font-semibold;
53
+ @apply tracking-wider;
54
+ }
55
+
56
+ .ag-header-cell-resize::after {
57
+ height: 100%;
58
+ top: 0;
59
+ @apply bg-gray-400;
60
+ }
61
+
62
+ .ag-right-aligned-header {
63
+ text-align: right;
64
+ }
65
+
66
+ .ag-pinned-left-header,
67
+ .ag-cell.ag-cell-last-left-pinned:not(.ag-cell-range-right):not(.ag-cell-range-single-cell) {
68
+ @apply border-gray-450;
69
+ @apply border-r-4;
70
+ @apply border-t-0;
71
+ @apply border-l-0;
72
+ @apply border-b-0;
73
+ }
74
+
75
+ .ag-row {
76
+ @apply border-t-0;
77
+ @apply border-l-0;
78
+ @apply border-r-0;
79
+ }
80
+
81
+ .ag-cell-value {
82
+ @apply text-gray-750;
83
+ @apply font-sans;
84
+ }
85
+
86
+ .ag-body-viewport {
87
+ ::-webkit-scrollbar {
88
+ // -webkit-appearance: none;
89
+ height: 8px;
90
+ @apply bg-gray-600;
91
+ }
92
+
93
+ ::-webkit-scrollbar-thumb {
94
+ border-radius: 8px;
95
+ @apply bg-gray-600;
96
+ }
97
+
98
+ ::-webkit-scrollbar-track {
99
+ @apply bg-gray-100;
100
+ -webkit-box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.7);
101
+ box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.7);
102
+ }
103
+ }
104
+
105
+ .ag-root-wrapper {
106
+ @apply border-b-0;
107
+ @apply rounded-t-md;
108
+ @apply rounded-b-none;
109
+ overflow: visible;
110
+ }
111
+ }
112
+
113
+ .data-pager {
114
+ @apply p-4;
115
+ @apply flex;
116
+ @apply items-center;
117
+ @apply border;
118
+ @apply border-t-0;
119
+ @apply rounded-b-md;
120
+ @apply border-gray-500;
121
+ @apply bg-gray-200;
122
+ }
123
+
124
+ .data-pager__control {
125
+ @apply px-4;
126
+
127
+ .field-label {
128
+ @apply mr-2;
129
+ }
130
+
131
+ &.field {
132
+ select {
133
+ @apply bg-white;
134
+ }
135
+ }
136
+ }
137
+
138
+ .data-pager__control-group {
139
+ margin-left: auto;
140
+ }
@@ -0,0 +1,56 @@
1
+ .hero {
2
+ @apply bg-primary-darker;
3
+ @apply py-10;
4
+ @apply px-5;
5
+ @apply text-white;
6
+ @apply text-center;
7
+ @apply bg-cover;
8
+
9
+ @screen md {
10
+ @apply py-20;
11
+ }
12
+
13
+ &.centered {
14
+ background-position: center center;
15
+ }
16
+ }
17
+
18
+ .hero__button,
19
+ .with_secondary a {
20
+ width: 100%;
21
+ }
22
+
23
+ .hero__title {
24
+ @apply text-4xl;
25
+ @apply mb-5;
26
+ @apply mx-auto;
27
+ letter-spacing: -0.04em;
28
+ max-width: 41rem;
29
+
30
+ @screen md {
31
+ @apply text-6xl;
32
+ @apply mb-8;
33
+ }
34
+
35
+ em {
36
+ @apply not-italic;
37
+ @apply underline;
38
+ -webkit-text-decoration-color: $tailwind-warn;
39
+ -moz-text-decoration-color: $tailwind-warn;
40
+ text-decoration-color: $tailwind-warn;
41
+ }
42
+ }
43
+
44
+ h2.hero__subtitle {
45
+ @apply font-sans;
46
+ @apply text-base;
47
+ @apply text-gray-100;
48
+ @apply mb-8;
49
+ @apply mx-auto;
50
+ max-width: 41rem;
51
+ text-shadow: 1px 2px 5px rgba(0, 0, 0, 0.5);
52
+
53
+ @screen md {
54
+ @apply text-lg;
55
+ }
56
+ }
@@ -0,0 +1,76 @@
1
+ import * as React from "react"
2
+ import { LinkButton } from "../actions/LinkButton"
3
+ import { Listing } from "@bloom-housing/backend-core/types"
4
+ import moment from "moment"
5
+ import { t } from "../helpers/translator"
6
+ import { openDateState } from "../helpers/state"
7
+ import "./Hero.scss"
8
+
9
+ export interface HeroProps {
10
+ title: React.ReactNode
11
+ backgroundImage?: string
12
+ buttonTitle?: string
13
+ buttonLink?: string
14
+ secondaryButtonTitle?: string
15
+ secondaryButtonLink?: string
16
+ listings?: Listing[]
17
+ children?: React.ReactNode
18
+ centered?: boolean
19
+ }
20
+
21
+ const listingOpen = (listing: Listing) => {
22
+ return moment() < moment(listing.applicationDueDate)
23
+ }
24
+
25
+ const HeroButton = (props: { title: string; href: string; className?: string }) => (
26
+ <span className={props.className + " hero__button"}>
27
+ <LinkButton href={props.href}>{props.title}</LinkButton>
28
+ </span>
29
+ )
30
+
31
+ const Hero = (props: HeroProps) => {
32
+ let subHeader, styles
33
+ let classNames = ""
34
+ if (props.listings) {
35
+ if (!props.listings.some(listingOpen) && !props.listings.some(openDateState)) {
36
+ subHeader = <h2 className="hero__subtitle">{t("welcome.allApplicationClosed")}</h2>
37
+ }
38
+ } else if (props.children) {
39
+ subHeader = <h2 className="hero__subtitle">{props.children}</h2>
40
+ }
41
+ if (props.backgroundImage) {
42
+ styles = { backgroundImage: `url(${props.backgroundImage})` }
43
+ }
44
+ if (props.centered) {
45
+ classNames = "centered"
46
+ }
47
+ return (
48
+ <div className={`hero ${classNames}`} style={styles}>
49
+ <h1 className="hero__title">{props.title}</h1>
50
+ {subHeader}
51
+
52
+ {props.buttonTitle && props.buttonLink && (
53
+ <>
54
+ {props.secondaryButtonTitle && props.secondaryButtonLink ? (
55
+ <div className="grid md:grid-cols-6 gap-5 ">
56
+ <HeroButton
57
+ className={"md:col-start-3 with_secondary"}
58
+ href={props.buttonLink}
59
+ title={props.buttonTitle}
60
+ />
61
+ <HeroButton
62
+ className={"with_secondary"}
63
+ href={props.secondaryButtonLink}
64
+ title={props.secondaryButtonTitle}
65
+ />
66
+ </div>
67
+ ) : (
68
+ <HeroButton className={"px-5"} href={props.buttonLink} title={props.buttonTitle} />
69
+ )}
70
+ </>
71
+ )}
72
+ </div>
73
+ )
74
+ }
75
+
76
+ export { Hero as default, Hero }
@@ -0,0 +1,31 @@
1
+ .page-header {
2
+ @apply py-8;
3
+
4
+ @screen md {
5
+ @apply py-10;
6
+ }
7
+
8
+ &.bg-primary-dark {
9
+ @apply text-white;
10
+ }
11
+ }
12
+
13
+ .page-header__group {
14
+ @apply px-5;
15
+ @apply m-auto;
16
+ @apply max-w-5xl;
17
+ }
18
+
19
+ .page-header__title {
20
+ @apply text-center;
21
+
22
+ @screen md {
23
+ @apply text-5xl;
24
+ @apply text-left;
25
+ }
26
+ }
27
+
28
+ .page-header__lead {
29
+ @apply m-auto;
30
+ @apply max-w-5xl;
31
+ }
@@ -0,0 +1,39 @@
1
+ import * as React from "react"
2
+ import "./PageHeader.scss"
3
+
4
+ export interface PageHeaderProps {
5
+ className?: string
6
+ inverse?: boolean
7
+ title: React.ReactNode
8
+ subtitle?: string
9
+ children?: React.ReactNode
10
+ tabNav?: React.ReactNode
11
+ }
12
+
13
+ const PageHeader = (props: PageHeaderProps) => {
14
+ const classNames = ["page-header"]
15
+ if (props.className) {
16
+ classNames.push(...props.className.split(" "))
17
+ }
18
+
19
+ if (props.inverse) {
20
+ classNames.push("bg-primary-dark")
21
+ classNames.push("text-white")
22
+ } else {
23
+ classNames.push("bg-primary-lighter")
24
+ }
25
+
26
+ return (
27
+ <header className={classNames.join(" ")}>
28
+ <hgroup className="page-header__group">
29
+ <h1 className="page-header__title">{props.title}</h1>
30
+ {props.subtitle && <p className="page-header__lead"> {props.subtitle}</p>}
31
+ {props.children}
32
+
33
+ {props.tabNav ? props.tabNav : null}
34
+ </hgroup>
35
+ </header>
36
+ )
37
+ }
38
+
39
+ export { PageHeader as default, PageHeader }
@@ -0,0 +1,136 @@
1
+ import React, { useState } from "react"
2
+ import { LocalizedLink } from "../actions/LocalizedLink"
3
+ import { LanguageNav, LangItem } from "../navigation/LanguageNav"
4
+
5
+ export interface SiteHeaderLanguage {
6
+ list: LangItem[]
7
+ codes: string[]
8
+ }
9
+ type LogoWidth = "slim" | "medium" | "wide"
10
+
11
+ export interface SiteHeaderProps {
12
+ logoSrc: string
13
+ title: string
14
+ imageOnly?: boolean
15
+ skip: string
16
+ notice: string | React.ReactNode
17
+ children: React.ReactNode
18
+ language?: SiteHeaderLanguage
19
+ logoClass?: string
20
+ logoWidth?: LogoWidth
21
+ }
22
+
23
+ export interface SiteHeaderState {
24
+ active: boolean
25
+ }
26
+
27
+ export interface NavbarDropdownProps {
28
+ menuTitle: string
29
+ children: React.ReactNode
30
+ }
31
+
32
+ export const NavbarDropdown = (props: NavbarDropdownProps) => {
33
+ return (
34
+ <div className="navbar-item has-dropdown is-hoverable" tabIndex={0}>
35
+ <a className="navbar-link">{props.menuTitle}</a>
36
+ <div className="navbar-dropdown">{props.children}</div>
37
+ </div>
38
+ )
39
+ }
40
+
41
+ const SiteHeader = (props: SiteHeaderProps) => {
42
+ const [active, setActive] = useState(false)
43
+
44
+ const skipLink = () => {
45
+ return (
46
+ <a href="#main-content" className="navbar__skip-link">
47
+ {props.skip}
48
+ </a>
49
+ )
50
+ }
51
+
52
+ const noticeBar = () => {
53
+ return (
54
+ <div className="navbar-notice">
55
+ <div className="navbar-notice__text">{props.notice}</div>
56
+ </div>
57
+ )
58
+ }
59
+
60
+ const getLogoWidthClass = () => {
61
+ if (props.logoWidth === "slim") return "navbar-width-slim"
62
+ if (props.logoWidth === "medium") return "navbar-width-med"
63
+ if (props.logoWidth === "wide") return "navbar-width-wide"
64
+ return ""
65
+ }
66
+
67
+ const logo = (logoClass = "") => {
68
+ return (
69
+ <LocalizedLink
70
+ className={`navbar-item logo ${logoClass} ${getLogoWidthClass()}`}
71
+ href="/"
72
+ aria-label="homepage"
73
+ >
74
+ <div
75
+ className={`logo__lockup ${getLogoWidthClass()} ${
76
+ props.logoWidth && "navbar-custom-width"
77
+ } ${props.imageOnly && "navbar-image-only-container"}`}
78
+ >
79
+ <img
80
+ className={`logo__image ${props.imageOnly && "navbar-image-only"}`}
81
+ src={props.logoSrc}
82
+ alt={"Site logo"}
83
+ />
84
+ {!props.imageOnly && <div className="logo__title">{props.title}</div>}
85
+ </div>
86
+ </LocalizedLink>
87
+ )
88
+ }
89
+
90
+ const handleMenuToggle = () => {
91
+ setActive(!active)
92
+ }
93
+
94
+ const hamburgerMenu = () => {
95
+ return (
96
+ <a
97
+ role="button"
98
+ className={"navbar-burger burger" + (active ? " is-active" : "")}
99
+ aria-label="menu"
100
+ aria-expanded={active ? "true" : "false"}
101
+ data-target="navbarMenuLinks"
102
+ onClick={handleMenuToggle}
103
+ >
104
+ <span aria-hidden="true"></span>
105
+ <span aria-hidden="true"></span>
106
+ <span aria-hidden="true"></span>
107
+ </a>
108
+ )
109
+ }
110
+
111
+ return (
112
+ <>
113
+ {props.language && <LanguageNav language={props.language} />}
114
+
115
+ {skipLink()}
116
+ {noticeBar()}
117
+ <div className="navbar__wrapper">
118
+ <nav className="navbar" role="navigation" aria-label="main navigation">
119
+ <div className="navbar-brand">
120
+ {logo(props.logoClass)}
121
+ {hamburgerMenu()}
122
+ </div>
123
+
124
+ <div
125
+ id="navbarMenuLinks"
126
+ className={"navbar-menu md:mt-0" + (active ? " is-active" : "")}
127
+ >
128
+ <div className="navbar-end">{props.children}</div>
129
+ </div>
130
+ </nav>
131
+ </div>
132
+ </>
133
+ )
134
+ }
135
+
136
+ export { SiteHeader as default, SiteHeader }