@dhis2-ui/header-bar 10.16.2 → 10.16.3-alpha.1

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 (125) hide show
  1. package/package.json +17 -16
  2. package/src/__e2e__/header-bar.e2e.stories.js +26 -0
  3. package/src/__e2e__/stories/common.js +226 -0
  4. package/src/__e2e__/stories/custom-application-title.js +19 -0
  5. package/src/__e2e__/stories/default.js +13 -0
  6. package/src/__e2e__/stories/me-with-avatar.js +27 -0
  7. package/src/__e2e__/stories/modulesWithSpecialCharacters.js +229 -0
  8. package/src/__e2e__/stories/online-status-message.js +49 -0
  9. package/src/__e2e__/stories/pwa-enabled.js +17 -0
  10. package/src/__e2e__/stories/user-has-all-authority.js +20 -0
  11. package/src/__e2e__/stories/user-has-no-authorities.js +20 -0
  12. package/src/__e2e__/stories/user-has-web-interpretation-and-messaging-authority.js +22 -0
  13. package/src/__e2e__/stories/user-has-web-interpretation-authority.js +22 -0
  14. package/src/__e2e__/stories/user-has-web-messaging-authority.js +22 -0
  15. package/src/__e2e__/stories/with-debug-info-edge-cases.js +51 -0
  16. package/src/__e2e__/stories/with-special-app-name-character.js +23 -0
  17. package/src/__e2e__/stories/with-update-available-notification.js +39 -0
  18. package/src/__e2e__/stories/zero-unread-interpretations.js +19 -0
  19. package/src/__e2e__/stories/zero-unread-messages.js +19 -0
  20. package/src/apps.js +276 -0
  21. package/src/debug-info/debug-info-menu-item.js +72 -0
  22. package/src/debug-info/debug-info-modal.js +47 -0
  23. package/src/debug-info/debug-info-table.js +51 -0
  24. package/src/debug-info/use-debug-info.js +15 -0
  25. package/src/features/common/index.js +14 -0
  26. package/src/features/the_headerbar_can_display_online_status/the_headerbar_displays_online_status.js +158 -0
  27. package/src/features/the_headerbar_can_display_online_status.feature +57 -0
  28. package/src/features/the_headerbar_conditionally_renders_notification_icons/the_headerbar_conditionally_renders_notification_icons.js +43 -0
  29. package/src/features/the_headerbar_conditionally_renders_notification_icons.feature +26 -0
  30. package/src/features/the_headerbar_contains_a_menu_to_all_apps/common.js +5 -0
  31. package/src/features/the_headerbar_contains_a_menu_to_all_apps/the_app_menu_closes_when_the_user_clicks_outside.js +9 -0
  32. package/src/features/the_headerbar_contains_a_menu_to_all_apps/the_headerbar_contains_a_menu_icon.js +5 -0
  33. package/src/features/the_headerbar_contains_a_menu_to_all_apps/the_user_will_be_offered_a_menu_with_5_apps.js +16 -0
  34. package/src/features/the_headerbar_contains_a_menu_to_all_apps.feature +21 -0
  35. package/src/features/the_headerbar_contains_a_profile_menu/common.js +14 -0
  36. package/src/features/the_headerbar_contains_a_profile_menu/the_headerbar_shows_a_text_icon_if_the_user_does_not_have_an_avatar.js +30 -0
  37. package/src/features/the_headerbar_contains_a_profile_menu/the_headerbar_shows_an_image_icon_if_the_user_has_an_avatar.js +23 -0
  38. package/src/features/the_headerbar_contains_a_profile_menu/the_menu_is_closed_by_default.js +1 -0
  39. package/src/features/the_headerbar_contains_a_profile_menu/the_menu_opens.js +14 -0
  40. package/src/features/the_headerbar_contains_a_profile_menu/the_profile_menu_closes_when_the_user_clicks_outside.js +5 -0
  41. package/src/features/the_headerbar_contains_a_profile_menu/the_user_can_edit_his_profile.js +7 -0
  42. package/src/features/the_headerbar_contains_a_profile_menu/the_user_can_go_to_his_account.js +7 -0
  43. package/src/features/the_headerbar_contains_a_profile_menu/the_user_can_go_to_the_about_dhis2_page.js +7 -0
  44. package/src/features/the_headerbar_contains_a_profile_menu/the_user_can_go_to_the_help_page.js +7 -0
  45. package/src/features/the_headerbar_contains_a_profile_menu/the_user_can_go_to_the_settings.js +7 -0
  46. package/src/features/the_headerbar_contains_a_profile_menu/the_user_can_log_out.js +53 -0
  47. package/src/features/the_headerbar_contains_a_profile_menu/the_user_name_and_email_are_displayed.js +22 -0
  48. package/src/features/the_headerbar_contains_a_profile_menu.feature +73 -0
  49. package/src/features/the_headerbar_displays_a_link_to_interpretations_and_an_unread_count/the_headerbar_displays_a_link_to_the_interpretations.js +5 -0
  50. package/src/features/the_headerbar_displays_a_link_to_interpretations_and_an_unread_count/there_are_no_unread_interpretations.js +9 -0
  51. package/src/features/the_headerbar_displays_a_link_to_interpretations_and_an_unread_count/there_are_some_unread_interpretations.js +12 -0
  52. package/src/features/the_headerbar_displays_a_link_to_interpretations_and_an_unread_count.feature +13 -0
  53. package/src/features/the_headerbar_displays_a_link_to_messages_and_an_unread_count/the_headerbar_displays_a_link_to_the_messages.js +5 -0
  54. package/src/features/the_headerbar_displays_a_link_to_messages_and_an_unread_count/there_are_no_unread_messages.js +9 -0
  55. package/src/features/the_headerbar_displays_a_link_to_messages_and_an_unread_count/there_are_some_unread_messages.js +7 -0
  56. package/src/features/the_headerbar_displays_a_link_to_messages_and_an_unread_count.feature +13 -0
  57. package/src/features/the_headerbar_should_contain_a_logo_that_links_to_the_homepage/headerbar_contains_logo.js +12 -0
  58. package/src/features/the_headerbar_should_contain_a_logo_that_links_to_the_homepage.feature +6 -0
  59. package/src/features/the_headerbar_should_display_app_update_notification/index.js +52 -0
  60. package/src/features/the_headerbar_should_display_app_update_notification.feature +22 -0
  61. package/src/features/the_headerbar_should_display_debug_version_infos/index.js +130 -0
  62. package/src/features/the_headerbar_should_display_debug_version_infos.feature +52 -0
  63. package/src/features/the_headerbar_should_display_the_title_provided_by_the_backend_and_the_app/the_headerbar_displays_the_custom_title.js +11 -0
  64. package/src/features/the_headerbar_should_display_the_title_provided_by_the_backend_and_the_app.feature +5 -0
  65. package/src/features/the_search_should_escape_regexp_character/common.js +6 -0
  66. package/src/features/the_search_should_escape_regexp_character/the_modules_do_not_contain_items_with_special_chars.js +23 -0
  67. package/src/features/the_search_should_escape_regexp_character/the_user_searches_for_an_app_with_a_regex_character.js +29 -0
  68. package/src/features/the_search_should_escape_regexp_character.feature +48 -0
  69. package/src/header-bar-context.js +28 -0
  70. package/src/header-bar.js +145 -0
  71. package/src/header-bar.prod.stories.js +303 -0
  72. package/src/index.js +1 -0
  73. package/src/join-path.js +4 -0
  74. package/src/locales/ar/translations.json +24 -0
  75. package/src/locales/ar_IQ/translations.json +24 -0
  76. package/src/locales/bn/translations.json +12 -0
  77. package/src/locales/ckb/translations.json +23 -0
  78. package/src/locales/cs/translations.json +24 -0
  79. package/src/locales/da/translations.json +24 -0
  80. package/src/locales/en/translations.json +25 -0
  81. package/src/locales/en_US/translations.json +25 -0
  82. package/src/locales/es/translations.json +25 -0
  83. package/src/locales/es_419/translations.json +24 -0
  84. package/src/locales/fr/translations.json +25 -0
  85. package/src/locales/hi_IN/translations.json +25 -0
  86. package/src/locales/id/translations.json +24 -0
  87. package/src/locales/index.js +88 -0
  88. package/src/locales/km/translations.json +24 -0
  89. package/src/locales/lo/translations.json +24 -0
  90. package/src/locales/my/translations.json +24 -0
  91. package/src/locales/nb/translations.json +24 -0
  92. package/src/locales/nl/translations.json +24 -0
  93. package/src/locales/or/translations.json +12 -0
  94. package/src/locales/prs/translations.json +24 -0
  95. package/src/locales/ps/translations.json +24 -0
  96. package/src/locales/pt/translations.json +25 -0
  97. package/src/locales/pt_BR/translations.json +24 -0
  98. package/src/locales/ro/translations.json +23 -0
  99. package/src/locales/ru/translations.json +24 -0
  100. package/src/locales/si/translations.json +24 -0
  101. package/src/locales/sv/translations.json +24 -0
  102. package/src/locales/tet/translations.json +24 -0
  103. package/src/locales/tg/translations.json +24 -0
  104. package/src/locales/uk/translations.json +24 -0
  105. package/src/locales/ur/translations.json +24 -0
  106. package/src/locales/uz_Latn/translations.json +23 -0
  107. package/src/locales/uz_UZ_Cyrl/translations.json +24 -0
  108. package/src/locales/uz_UZ_Latn/translations.json +24 -0
  109. package/src/locales/vi/translations.json +24 -0
  110. package/src/locales/zh/translations.json +25 -0
  111. package/src/locales/zh_CN/translations.json +24 -0
  112. package/src/logo-image.js +71 -0
  113. package/src/logo.js +45 -0
  114. package/src/notification-icon.js +91 -0
  115. package/src/notifications.js +63 -0
  116. package/src/online-status.js +40 -0
  117. package/src/online-status.styles.js +91 -0
  118. package/src/profile/use-on-doc-click.js +23 -0
  119. package/src/profile/use-on-doc-click.test.js +40 -0
  120. package/src/profile-menu/index.js +1 -0
  121. package/src/profile-menu/profile-header.js +118 -0
  122. package/src/profile-menu/profile-menu.js +176 -0
  123. package/src/profile-menu/update-notification.js +67 -0
  124. package/src/profile.js +101 -0
  125. package/src/title.js +23 -0
@@ -0,0 +1,118 @@
1
+ import { useConfig } from '@dhis2/app-runtime'
2
+ import { UserAvatar } from '@dhis2-ui/user-avatar'
3
+ import PropTypes from 'prop-types'
4
+ import React from 'react'
5
+ import { joinPath } from '../join-path.js'
6
+ import i18n from '../locales/index.js'
7
+
8
+ const ProfileName = ({ children }) => (
9
+ <div data-test="headerbar-profile-username">
10
+ {children}
11
+
12
+ <style jsx>{`
13
+ div {
14
+ margin-bottom: 3px;
15
+ font-size: 16px;
16
+ line-height: 19px;
17
+ }
18
+ `}</style>
19
+ </div>
20
+ )
21
+ ProfileName.propTypes = {
22
+ children: PropTypes.string,
23
+ }
24
+
25
+ const ProfileEmail = ({ children }) => (
26
+ <div data-test="headerbar-profile-user-email">
27
+ {children}
28
+
29
+ <style jsx>{`
30
+ div {
31
+ margin-bottom: 6px;
32
+ font-size: 14px;
33
+ line-height: 16px;
34
+ }
35
+ `}</style>
36
+ </div>
37
+ )
38
+ ProfileEmail.propTypes = {
39
+ children: PropTypes.string,
40
+ }
41
+
42
+ const ProfileEdit = ({ children }) => {
43
+ const { baseUrl } = useConfig()
44
+
45
+ return (
46
+ <a
47
+ href={joinPath(baseUrl, 'dhis-web-user-profile/#/profile')}
48
+ data-test="headerbar-profile-edit-profile-link"
49
+ >
50
+ {children}
51
+
52
+ <style jsx>{`
53
+ a {
54
+ color: rgba(0, 0, 0, 0.87);
55
+ font-size: 12px;
56
+ line-height: 14px;
57
+ text-decoration: underline;
58
+ cursor: pointer;
59
+ }
60
+ `}</style>
61
+ </a>
62
+ )
63
+ }
64
+
65
+ ProfileEdit.propTypes = {
66
+ children: PropTypes.string,
67
+ }
68
+
69
+ const ProfileDetails = ({ name, email }) => (
70
+ <div>
71
+ <ProfileName>{name}</ProfileName>
72
+ <ProfileEmail>{email}</ProfileEmail>
73
+ <ProfileEdit>{i18n.t('Edit profile')}</ProfileEdit>
74
+
75
+ <style jsx>{`
76
+ div {
77
+ display: flex;
78
+ flex-direction: column;
79
+ margin-inline-start: 20px;
80
+ color: #000;
81
+ font-size: 14px;
82
+ font-weight: 400;
83
+ }
84
+ `}</style>
85
+ </div>
86
+ )
87
+
88
+ ProfileDetails.propTypes = {
89
+ email: PropTypes.string,
90
+ name: PropTypes.string,
91
+ }
92
+
93
+ export const ProfileHeader = ({ name, email, avatarId }) => (
94
+ <div>
95
+ <UserAvatar
96
+ avatarId={avatarId}
97
+ name={name}
98
+ dataTest="headerbar-profile-menu-icon"
99
+ large
100
+ />
101
+ <ProfileDetails name={name} email={email} />
102
+
103
+ <style jsx>{`
104
+ div {
105
+ display: flex;
106
+ flex-direction: row;
107
+ margin-inline-start: 24px;
108
+ padding-top: 20px;
109
+ }
110
+ `}</style>
111
+ </div>
112
+ )
113
+
114
+ ProfileHeader.propTypes = {
115
+ avatarId: PropTypes.string,
116
+ email: PropTypes.string,
117
+ name: PropTypes.string,
118
+ }
@@ -0,0 +1,176 @@
1
+ import { clearSensitiveCaches, useConfig } from '@dhis2/app-runtime'
2
+ import { colors } from '@dhis2/ui-constants'
3
+ import {
4
+ IconSettings24,
5
+ IconInfo24,
6
+ IconLogOut24,
7
+ IconUser24,
8
+ IconQuestion24,
9
+ } from '@dhis2/ui-icons'
10
+ import { Card } from '@dhis2-ui/card'
11
+ import { Center } from '@dhis2-ui/center'
12
+ import { Divider } from '@dhis2-ui/divider'
13
+ import { Layer } from '@dhis2-ui/layer'
14
+ import { CircularLoader } from '@dhis2-ui/loader'
15
+ import { MenuDivider, MenuItem } from '@dhis2-ui/menu'
16
+ import PropTypes from 'prop-types'
17
+ import React, { useState } from 'react'
18
+ import { DebugInfoMenuItem } from '../debug-info/debug-info-menu-item.js'
19
+ import { joinPath } from '../join-path.js'
20
+ import i18n from '../locales/index.js'
21
+ import { ProfileHeader } from './profile-header.js'
22
+ import { UpdateNotification } from './update-notification.js'
23
+
24
+ const LoadingMask = () => (
25
+ <Layer
26
+ translucent
27
+ disablePortal
28
+ dataTest="headerbar-profile-menu-loading-mask"
29
+ >
30
+ <Center>
31
+ <CircularLoader />
32
+ </Center>
33
+ </Layer>
34
+ )
35
+
36
+ const ProfileContents = ({
37
+ name,
38
+ email,
39
+ avatarId,
40
+ helpUrl,
41
+ hideProfileMenu,
42
+ showDebugInfoModal,
43
+ }) => {
44
+ const { baseUrl } = useConfig()
45
+ const [loading, setLoading] = useState(false)
46
+
47
+ return (
48
+ <Card>
49
+ <div>
50
+ <ProfileHeader name={name} email={email} avatarId={avatarId} />
51
+ <Divider margin="13px 0 7px 0" />
52
+ <ul data-test="headerbar-profile-menu">
53
+ <MenuItem
54
+ href={joinPath(
55
+ baseUrl,
56
+ 'dhis-web-user-profile/#/settings'
57
+ )}
58
+ label={i18n.t('Settings')}
59
+ value="settings"
60
+ icon={<IconSettings24 color={colors.grey700} />}
61
+ />
62
+ <MenuItem
63
+ href={joinPath(
64
+ baseUrl,
65
+ 'dhis-web-user-profile/#/account'
66
+ )}
67
+ label={i18n.t('Account')}
68
+ value="account"
69
+ icon={<IconUser24 color={colors.grey700} />}
70
+ />
71
+ {helpUrl && (
72
+ <MenuItem
73
+ href={helpUrl}
74
+ label={i18n.t('Help')}
75
+ value="help"
76
+ icon={<IconQuestion24 color={colors.grey700} />}
77
+ />
78
+ )}
79
+ <MenuItem
80
+ href={joinPath(
81
+ baseUrl,
82
+ 'dhis-web-user-profile/#/aboutPage'
83
+ )}
84
+ label={i18n.t('About DHIS2')}
85
+ value="about"
86
+ icon={<IconInfo24 color={colors.grey700} />}
87
+ />
88
+ <MenuItem
89
+ href={joinPath(
90
+ baseUrl,
91
+ 'dhis-web-commons-security/logout.action'
92
+ )}
93
+ // NB: By MenuItem implementation, this callback
94
+ // overwrites default navigation behavior but maintains
95
+ // the href attribute
96
+ onClick={async () => {
97
+ setLoading(true)
98
+ await clearSensitiveCaches()
99
+ setLoading(false)
100
+ window.location.assign(
101
+ joinPath(
102
+ baseUrl,
103
+ 'dhis-web-commons-security/logout.action'
104
+ )
105
+ )
106
+ }}
107
+ label={i18n.t('Logout')}
108
+ value="logout"
109
+ icon={<IconLogOut24 color={colors.grey700} />}
110
+ />
111
+ <MenuDivider dense />
112
+ <DebugInfoMenuItem
113
+ hideProfileMenu={hideProfileMenu}
114
+ showDebugInfoModal={showDebugInfoModal}
115
+ />
116
+ <UpdateNotification hideProfileMenu={hideProfileMenu} />
117
+ </ul>
118
+ </div>
119
+
120
+ {loading && <LoadingMask />}
121
+
122
+ <style jsx>{`
123
+ div {
124
+ width: 100%;
125
+ padding: 0;
126
+ }
127
+
128
+ ul {
129
+ padding: 0;
130
+ margin: 0;
131
+ }
132
+
133
+ a,
134
+ a:hover,
135
+ a:focus,
136
+ a:active,
137
+ a:visited {
138
+ text-decoration: none;
139
+ display: block;
140
+ }
141
+ `}</style>
142
+ </Card>
143
+ )
144
+ }
145
+
146
+ ProfileContents.propTypes = {
147
+ hideProfileMenu: PropTypes.func.isRequired,
148
+ showDebugInfoModal: PropTypes.func.isRequired,
149
+ avatarId: PropTypes.string,
150
+ email: PropTypes.string,
151
+ helpUrl: PropTypes.string,
152
+ name: PropTypes.string,
153
+ }
154
+
155
+ export const ProfileMenu = ({ ...props }) => (
156
+ <div data-test="headerbar-profile-menu">
157
+ <ProfileContents {...props} />
158
+ <style jsx>{`
159
+ div {
160
+ z-index: 10000;
161
+ position: absolute;
162
+ inset-inline-end: 4px;
163
+ width: 320px;
164
+ }
165
+ `}</style>
166
+ </div>
167
+ )
168
+
169
+ ProfileMenu.propTypes = {
170
+ hideProfileMenu: PropTypes.func.isRequired,
171
+ showDebugInfoModal: PropTypes.func.isRequired,
172
+ avatarId: PropTypes.string,
173
+ email: PropTypes.string,
174
+ helpUrl: PropTypes.string,
175
+ name: PropTypes.string,
176
+ }
@@ -0,0 +1,67 @@
1
+ import { useConfig } from '@dhis2/app-runtime'
2
+ import { colors } from '@dhis2/ui-constants'
3
+ import { MenuItem } from '@dhis2-ui/menu'
4
+ import PropTypes from 'prop-types'
5
+ import React from 'react'
6
+ import { useHeaderBarContext } from '../header-bar-context.js'
7
+ import i18n from '../locales/index.js'
8
+
9
+ export function UpdateNotification({ hideProfileMenu }) {
10
+ const { appName } = useConfig()
11
+ const { updateAvailable, onApplyAvailableUpdate } = useHeaderBarContext()
12
+ const onClick = () => {
13
+ hideProfileMenu()
14
+ onApplyAvailableUpdate?.()
15
+ }
16
+
17
+ const updateNotificationLabel = (
18
+ <div className="root">
19
+ <div className="badge" />
20
+ <div className="spacer" />
21
+ <div className="message">
22
+ {appName
23
+ ? i18n.t('New {{appName}} version available', { appName })
24
+ : i18n.t('New app version available')}
25
+ <br />
26
+ {i18n.t('Click to reload')}
27
+ </div>
28
+ <style jsx>{`
29
+ .root {
30
+ display: flex;
31
+ flex-direction: row;
32
+ align-items: center;
33
+ font-size: 14px;
34
+ line-height: 17px;
35
+ }
36
+ .badge {
37
+ display: inline-block;
38
+ width: 12px;
39
+ height: 12px;
40
+ margin: 0 8px;
41
+ border-radius: 6px;
42
+ background-color: ${colors.blue600};
43
+ }
44
+ .spacer {
45
+ display: inline-block;
46
+ width: 8px;
47
+ }
48
+ .message {
49
+ display: inline-block;
50
+ }
51
+ `}</style>
52
+ </div>
53
+ )
54
+
55
+ return updateAvailable ? (
56
+ <MenuItem
57
+ dense
58
+ onClick={onClick}
59
+ label={updateNotificationLabel}
60
+ dataTest="dhis2-ui-headerbar-updatenotification"
61
+ />
62
+ ) : null
63
+ }
64
+
65
+ UpdateNotification.propTypes = {
66
+ hideProfileMenu: PropTypes.func.isRequired,
67
+ }
package/src/profile.js ADDED
@@ -0,0 +1,101 @@
1
+ import { UserAvatar } from '@dhis2-ui/user-avatar'
2
+ import PropTypes from 'prop-types'
3
+ import React, { useCallback, useRef, useState } from 'react'
4
+ import { DebugInfoModal } from './debug-info/debug-info-modal.js'
5
+ import i18n from './locales/index.js'
6
+ import { useOnDocClick } from './profile/use-on-doc-click.js'
7
+ import { ProfileMenu } from './profile-menu/index.js'
8
+
9
+ const Profile = ({ name, email, avatarId, helpUrl }) => {
10
+ const [showProfileMenu, setShowProfileMenu] = useState(false)
11
+ const [showDebugInfoModal, setShowDebugInfoModal] = useState(false)
12
+ const hideProfileMenu = useCallback(
13
+ () => setShowProfileMenu(false),
14
+ [setShowProfileMenu]
15
+ )
16
+ const toggleProfileMenu = useCallback(
17
+ () => setShowProfileMenu((show) => !show),
18
+ [setShowProfileMenu]
19
+ )
20
+ const containerRef = useRef(null)
21
+
22
+ useOnDocClick(containerRef, hideProfileMenu)
23
+
24
+ return (
25
+ <div
26
+ ref={containerRef}
27
+ data-test="headerbar-profile"
28
+ className="headerbar-profile"
29
+ >
30
+ <button
31
+ className="headerbar-profile-btn"
32
+ onClick={toggleProfileMenu}
33
+ title={i18n.t('Profile menu')}
34
+ aria-label={i18n.t('Profile menu')}
35
+ >
36
+ <UserAvatar
37
+ avatarId={avatarId}
38
+ name={name}
39
+ dataTest="headerbar-profile-icon"
40
+ medium
41
+ />
42
+ </button>
43
+
44
+ {showProfileMenu && (
45
+ <ProfileMenu
46
+ avatarId={avatarId}
47
+ name={name}
48
+ email={email}
49
+ helpUrl={helpUrl}
50
+ hideProfileMenu={hideProfileMenu}
51
+ showDebugInfoModal={() => {
52
+ setShowDebugInfoModal(true)
53
+ }}
54
+ />
55
+ )}
56
+ {showDebugInfoModal && (
57
+ <DebugInfoModal
58
+ onClose={() => {
59
+ setShowDebugInfoModal(false)
60
+ }}
61
+ />
62
+ )}
63
+
64
+ <style jsx>{`
65
+ .headerbar-profile {
66
+ position: relative;
67
+ height: 100%;
68
+ }
69
+
70
+ .headerbar-profile-btn {
71
+ background: transparent;
72
+ padding: 6px;
73
+ border: 0;
74
+ cursor: pointer;
75
+ }
76
+ .headerbar-profile-btn:focus {
77
+ outline: 2px solid white;
78
+ outline-offset: -2px;
79
+ }
80
+ .headerbar-profile-btn:focus:not(:focus-visible) {
81
+ outline: none;
82
+ }
83
+ .headerbar-profile-btn:hover {
84
+ background: #1a557f;
85
+ }
86
+ .headerbar-profile-btn:active {
87
+ background: #104067;
88
+ }
89
+ `}</style>
90
+ </div>
91
+ )
92
+ }
93
+
94
+ Profile.propTypes = {
95
+ name: PropTypes.string.isRequired,
96
+ avatarId: PropTypes.string,
97
+ email: PropTypes.string,
98
+ helpUrl: PropTypes.string,
99
+ }
100
+
101
+ export default Profile
package/src/title.js ADDED
@@ -0,0 +1,23 @@
1
+ import PropTypes from 'prop-types'
2
+ import React from 'react'
3
+
4
+ export const Title = ({ app, instance }) => (
5
+ <div data-test="headerbar-title">
6
+ {app ? `${instance} - ${app}` : `${instance}`}
7
+
8
+ <style jsx>{`
9
+ div {
10
+ overflow: hidden;
11
+ text-overflow: ellipsis;
12
+ font-size: 14px;
13
+ font-weight: 500;
14
+ letter-spacing: 0.01em;
15
+ white-space: nowrap;
16
+ }
17
+ `}</style>
18
+ </div>
19
+ )
20
+ Title.propTypes = {
21
+ app: PropTypes.string,
22
+ instance: PropTypes.string,
23
+ }