@ndla/ui 13.2.2 → 15.1.0
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.
- package/es/Article/Article.js +22 -3
- package/es/Article/ArticleFavoritesButton.js +38 -0
- package/es/Article/index.js +2 -1
- package/es/Breadcrumb/ActionBreadcrumb.js +57 -0
- package/es/Breadcrumb/index.js +1 -0
- package/es/Footer/FooterAuth.js +15 -22
- package/es/InfoBlock/InfoBlock.js +55 -0
- package/es/InfoBlock/index.js +1 -0
- package/es/LearningPaths/LearningPathMenu.js +3 -4
- package/es/Masthead/MastheadAuthModal.js +2 -2
- package/es/MyNdla/Navigation/VerticalNavigation.js +51 -0
- package/es/MyNdla/Navigation/index.js +2 -0
- package/es/MyNdla/Resource/Folder.js +86 -0
- package/es/MyNdla/Resource/FolderInput.js +96 -0
- package/{lib/MyNdla/ResourceDash/ResourcesView.d.ts → es/MyNdla/Resource/index.js} +3 -3
- package/es/MyNdla/index.js +4 -4
- package/es/Resource/BlockResource.js +73 -0
- package/es/Resource/ListResource.js +66 -0
- package/es/Resource/index.js +10 -0
- package/es/Resource/resourceComponents.js +97 -0
- package/es/ResourceGroup/ResourceGroup.js +7 -5
- package/es/ResourceGroup/ResourceItem.js +28 -30
- package/es/ResourceGroup/ResourceList.js +18 -6
- package/es/Search/ActiveFilters.js +6 -7
- package/es/Search/ContentTypeResult.js +6 -8
- package/es/SearchTypeResult/ActiveFilters.js +6 -10
- package/es/SnackBar/SnackBar.js +117 -0
- package/es/SnackBar/index.js +9 -0
- package/es/TagSelector/SuggestionInput.js +240 -0
- package/es/TagSelector/Suggestions.js +93 -0
- package/es/TagSelector/TagSelector.js +137 -0
- package/es/TagSelector/index.js +9 -0
- package/es/TopicIntroductionList/TopicIntroduction.js +2 -4
- package/es/TopicIntroductionList/TopicShortcutItem.js +1 -3
- package/es/TreeStructure/FolderItem.js +130 -0
- package/es/TreeStructure/FolderItems.js +123 -0
- package/es/TreeStructure/FolderNameInput.js +112 -0
- package/es/TreeStructure/TreeStructure.js +254 -0
- package/es/TreeStructure/TreeStructure.types.js +0 -0
- package/es/TreeStructure/TreeStructureWrapper.js +13 -0
- package/es/TreeStructure/helperFunctions.js +92 -0
- package/es/TreeStructure/index.js +9 -0
- package/es/TreeStructure/keyboardNavigation/keyboardNavigation.js +182 -0
- package/es/TreeStructure/keyboardNavigation/keyboardNavigation.types.js +0 -0
- package/es/User/AuthModal.js +15 -24
- package/es/User/UserInfo.js +70 -0
- package/es/User/apiTypes.js +0 -0
- package/es/User/index.js +2 -0
- package/es/User/parseUserObject.js +102 -0
- package/es/all.css +90 -0
- package/es/index.js +9 -3
- package/es/locale/messages-en.js +71 -4
- package/es/locale/messages-nb.js +70 -3
- package/es/locale/messages-nn.js +70 -3
- package/es/locale/messages-se.js +70 -3
- package/es/locale/messages-sma.js +70 -3
- package/lib/Article/Article.d.ts +3 -1
- package/lib/Article/Article.js +43 -23
- package/lib/Article/ArticleFavoritesButton.d.ts +15 -0
- package/lib/Article/ArticleFavoritesButton.js +56 -0
- package/lib/Article/index.d.ts +2 -1
- package/lib/Article/index.js +8 -0
- package/lib/Breadcrumb/ActionBreadcrumb.d.ts +16 -0
- package/lib/Breadcrumb/ActionBreadcrumb.js +72 -0
- package/lib/Breadcrumb/index.d.ts +1 -0
- package/lib/Breadcrumb/index.js +8 -0
- package/lib/Footer/FooterAuth.d.ts +1 -1
- package/lib/Footer/FooterAuth.js +17 -17
- package/lib/InfoBlock/InfoBlock.d.ts +8 -0
- package/lib/InfoBlock/InfoBlock.js +58 -0
- package/lib/InfoBlock/index.d.ts +1 -0
- package/lib/InfoBlock/index.js +13 -0
- package/lib/LearningPaths/LearningPathMenu.js +3 -4
- package/lib/Masthead/MastheadAuthModal.d.ts +3 -3
- package/lib/Masthead/MastheadAuthModal.js +3 -3
- package/lib/MyNdla/Navigation/VerticalNavigation.d.ts +10 -0
- package/lib/MyNdla/Navigation/VerticalNavigation.js +61 -0
- package/lib/MyNdla/Navigation/index.d.ts +2 -0
- package/lib/MyNdla/Navigation/index.js +15 -0
- package/lib/MyNdla/Resource/Folder.d.ts +20 -0
- package/lib/MyNdla/Resource/Folder.js +100 -0
- package/lib/MyNdla/Resource/FolderInput.d.ts +15 -0
- package/lib/MyNdla/Resource/FolderInput.js +116 -0
- package/lib/MyNdla/Resource/index.d.ts +10 -0
- package/lib/MyNdla/Resource/index.js +23 -0
- package/lib/MyNdla/index.d.ts +4 -4
- package/lib/MyNdla/index.js +13 -7
- package/lib/Resource/BlockResource.d.ts +20 -0
- package/lib/Resource/BlockResource.js +84 -0
- package/lib/Resource/ListResource.d.ts +20 -0
- package/lib/Resource/ListResource.js +78 -0
- package/lib/Resource/index.d.ts +11 -0
- package/lib/Resource/index.js +29 -0
- package/lib/Resource/resourceComponents.d.ts +24 -0
- package/lib/Resource/resourceComponents.js +106 -0
- package/lib/ResourceGroup/ResourceGroup.d.ts +2 -1
- package/lib/ResourceGroup/ResourceGroup.js +7 -5
- package/lib/ResourceGroup/ResourceItem.d.ts +5 -1
- package/lib/ResourceGroup/ResourceItem.js +29 -30
- package/lib/ResourceGroup/ResourceList.d.ts +3 -1
- package/lib/ResourceGroup/ResourceList.js +18 -6
- package/lib/Search/ActiveFilters.js +6 -7
- package/lib/Search/ContentTypeResult.js +6 -8
- package/lib/SearchTypeResult/ActiveFilters.js +6 -10
- package/lib/SnackBar/SnackBar.d.ts +23 -0
- package/lib/SnackBar/SnackBar.js +127 -0
- package/lib/SnackBar/index.d.ts +10 -0
- package/lib/SnackBar/index.js +15 -0
- package/lib/TagSelector/SuggestionInput.d.ts +19 -0
- package/lib/TagSelector/SuggestionInput.js +255 -0
- package/lib/TagSelector/Suggestions.d.ts +12 -0
- package/lib/TagSelector/Suggestions.js +96 -0
- package/lib/TagSelector/TagSelector.d.ts +16 -0
- package/lib/TagSelector/TagSelector.js +150 -0
- package/lib/TagSelector/index.d.ts +10 -0
- package/lib/TagSelector/index.js +19 -0
- package/lib/TopicIntroductionList/TopicIntroduction.js +2 -4
- package/lib/TopicIntroductionList/TopicShortcutItem.js +1 -3
- package/lib/TreeStructure/FolderItem.d.ts +27 -0
- package/lib/TreeStructure/FolderItem.js +140 -0
- package/lib/TreeStructure/FolderItems.d.ts +11 -0
- package/lib/TreeStructure/FolderItems.js +130 -0
- package/lib/TreeStructure/FolderNameInput.d.ts +15 -0
- package/lib/TreeStructure/FolderNameInput.js +125 -0
- package/lib/TreeStructure/TreeStructure.d.ts +12 -0
- package/lib/TreeStructure/TreeStructure.js +273 -0
- package/lib/TreeStructure/TreeStructure.types.d.ts +63 -0
- package/lib/TreeStructure/TreeStructure.types.js +1 -0
- package/lib/TreeStructure/TreeStructureWrapper.d.ts +12 -0
- package/lib/TreeStructure/TreeStructureWrapper.js +24 -0
- package/lib/TreeStructure/helperFunctions.d.ts +5 -0
- package/lib/TreeStructure/helperFunctions.js +103 -0
- package/lib/TreeStructure/index.d.ts +10 -0
- package/lib/TreeStructure/index.js +15 -0
- package/lib/TreeStructure/keyboardNavigation/keyboardNavigation.d.ts +11 -0
- package/lib/TreeStructure/keyboardNavigation/keyboardNavigation.js +186 -0
- package/lib/TreeStructure/keyboardNavigation/keyboardNavigation.types.d.ts +26 -0
- package/lib/TreeStructure/keyboardNavigation/keyboardNavigation.types.js +1 -0
- package/lib/User/AuthModal.d.ts +3 -3
- package/lib/User/AuthModal.js +16 -23
- package/lib/User/UserInfo.d.ts +13 -0
- package/lib/User/UserInfo.js +84 -0
- package/lib/User/apiTypes.d.ts +61 -0
- package/lib/User/apiTypes.js +1 -0
- package/lib/User/index.d.ts +4 -0
- package/lib/User/index.js +8 -0
- package/lib/User/parseUserObject.d.ts +32 -0
- package/lib/User/parseUserObject.js +105 -0
- package/lib/all.css +90 -0
- package/lib/index.d.ts +14 -3
- package/lib/index.js +83 -10
- package/lib/locale/messages-en.d.ts +67 -0
- package/lib/locale/messages-en.js +71 -4
- package/lib/locale/messages-nb.d.ts +67 -0
- package/lib/locale/messages-nb.js +70 -3
- package/lib/locale/messages-nn.d.ts +67 -0
- package/lib/locale/messages-nn.js +70 -3
- package/lib/locale/messages-se.d.ts +67 -0
- package/lib/locale/messages-se.js +70 -3
- package/lib/locale/messages-sma.d.ts +67 -0
- package/lib/locale/messages-sma.js +70 -3
- package/lib/types.d.ts +1 -1
- package/package.json +11 -11
- package/src/Article/Article.tsx +31 -0
- package/src/Article/ArticleFavoritesButton.tsx +40 -0
- package/src/Article/index.ts +2 -0
- package/src/Breadcrumb/ActionBreadcrumb.tsx +68 -0
- package/src/Breadcrumb/index.ts +2 -0
- package/src/Footer/FooterAuth.tsx +7 -9
- package/src/InfoBlock/InfoBlock.tsx +61 -0
- package/src/InfoBlock/index.ts +1 -0
- package/src/LearningPaths/LearningPathMenu.tsx +1 -1
- package/src/Masthead/MastheadAuthModal.tsx +4 -5
- package/src/MyNdla/Navigation/VerticalNavigation.tsx +93 -0
- package/src/MyNdla/Navigation/index.ts +2 -0
- package/src/MyNdla/Resource/Folder.tsx +145 -0
- package/src/MyNdla/Resource/FolderInput.tsx +104 -0
- package/src/MyNdla/Resource/index.ts +11 -0
- package/src/MyNdla/index.ts +4 -5
- package/src/Resource/BlockResource.tsx +101 -0
- package/src/Resource/ListResource.tsx +111 -0
- package/src/Resource/index.ts +12 -0
- package/src/Resource/resourceComponents.tsx +143 -0
- package/src/ResourceGroup/ResourceGroup.tsx +3 -0
- package/src/ResourceGroup/ResourceItem.tsx +20 -3
- package/src/ResourceGroup/ResourceList.tsx +16 -3
- package/src/Search/ActiveFilters.jsx +0 -1
- package/src/Search/ContentTypeResult.tsx +8 -9
- package/src/SearchTypeResult/ActiveFilters.tsx +1 -3
- package/src/SnackBar/SnackBar.tsx +183 -0
- package/src/SnackBar/index.ts +13 -0
- package/src/TagSelector/SuggestionInput.tsx +230 -0
- package/src/TagSelector/Suggestions.tsx +125 -0
- package/src/TagSelector/TagSelector.tsx +111 -0
- package/src/TagSelector/index.ts +13 -0
- package/src/TopicIntroductionList/TopicIntroduction.tsx +2 -2
- package/src/TopicIntroductionList/TopicShortcutItem.tsx +1 -5
- package/src/TreeStructure/FolderItem.tsx +160 -0
- package/src/TreeStructure/FolderItems.tsx +109 -0
- package/src/TreeStructure/FolderNameInput.tsx +109 -0
- package/src/TreeStructure/TreeStructure.tsx +184 -0
- package/src/TreeStructure/TreeStructure.types.ts +69 -0
- package/src/TreeStructure/TreeStructureWrapper.tsx +34 -0
- package/src/TreeStructure/helperFunctions.ts +52 -0
- package/src/TreeStructure/index.ts +11 -0
- package/src/TreeStructure/keyboardNavigation/keyboardNavigation.ts +161 -0
- package/src/TreeStructure/keyboardNavigation/keyboardNavigation.types.ts +28 -0
- package/src/User/AuthModal.tsx +5 -26
- package/src/User/UserInfo.tsx +80 -0
- package/src/User/__tests__/parseUserObject-test.ts +315 -0
- package/src/User/apiTypes.ts +74 -0
- package/src/User/index.ts +4 -0
- package/src/User/parseUserObject.ts +83 -0
- package/src/all.scss +2 -0
- package/src/index.ts +15 -4
- package/src/locale/messages-en.ts +65 -3
- package/src/locale/messages-nb.ts +64 -2
- package/src/locale/messages-nn.ts +64 -2
- package/src/locale/messages-se.ts +64 -2
- package/src/locale/messages-sma.ts +64 -2
- package/src/types.ts +1 -1
- package/es/MyNdla/ResourceDash/Breadcrumbs.js +0 -22
- package/es/MyNdla/ResourceDash/ResourceElement.js +0 -27
- package/es/MyNdla/ResourceDash/ResourcesView.js +0 -43
- package/es/MyNdla/ResourceDash/index.js +0 -4
- package/lib/MyNdla/ResourceDash/Breadcrumbs.d.ts +0 -15
- package/lib/MyNdla/ResourceDash/Breadcrumbs.js +0 -35
- package/lib/MyNdla/ResourceDash/ResourceElement.d.ts +0 -18
- package/lib/MyNdla/ResourceDash/ResourceElement.js +0 -38
- package/lib/MyNdla/ResourceDash/ResourcesView.js +0 -57
- package/lib/MyNdla/ResourceDash/index.d.ts +0 -4
- package/lib/MyNdla/ResourceDash/index.js +0 -31
- package/src/MyNdla/ResourceDash/Breadcrumbs.tsx +0 -31
- package/src/MyNdla/ResourceDash/ResourceElement.tsx +0 -50
- package/src/MyNdla/ResourceDash/ResourcesView.tsx +0 -42
- package/src/MyNdla/ResourceDash/index.ts +0 -5
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2022-present, NDLA.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the GPLv3 license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import styled from '@emotion/styled';
|
|
10
|
+
import { colors, fonts, spacing } from '@ndla/core';
|
|
11
|
+
import { ChevronRight } from '@ndla/icons/common';
|
|
12
|
+
import SafeLink from '@ndla/safelink';
|
|
13
|
+
import React from 'react';
|
|
14
|
+
import { MenuButton } from '@ndla/button';
|
|
15
|
+
import { MenuItemProps } from '@ndla/button';
|
|
16
|
+
import Breadcrumb from './Breadcrumb';
|
|
17
|
+
import { IndexedBreadcrumbItem, SimpleBreadcrumbItem } from './BreadcrumbItem';
|
|
18
|
+
|
|
19
|
+
const StyledRightChevron = styled(ChevronRight)`
|
|
20
|
+
color: ${colors.text.primary};
|
|
21
|
+
margin: ${spacing.xxsmall};
|
|
22
|
+
height: 24px;
|
|
23
|
+
width: 24px;
|
|
24
|
+
`;
|
|
25
|
+
|
|
26
|
+
const StyledSpan = styled.span`
|
|
27
|
+
color: ${colors.text.primary};
|
|
28
|
+
font-weight: ${fonts.weight.bold};
|
|
29
|
+
`;
|
|
30
|
+
|
|
31
|
+
const StyledSafeLink = styled(SafeLink)`
|
|
32
|
+
color: ${colors.text.primary};
|
|
33
|
+
box-shadow: none;
|
|
34
|
+
font-weight: ${fonts.weight.bold};
|
|
35
|
+
:hover {
|
|
36
|
+
color: ${colors.brand.primary};
|
|
37
|
+
}
|
|
38
|
+
`;
|
|
39
|
+
|
|
40
|
+
interface Props {
|
|
41
|
+
items: SimpleBreadcrumbItem[];
|
|
42
|
+
actionItems: MenuItemProps[];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const ActionBreadcrumb = ({ items, actionItems }: Props) => {
|
|
46
|
+
const renderItem = (item: IndexedBreadcrumbItem, totalCount: number) => {
|
|
47
|
+
if (item.index === totalCount - 1) {
|
|
48
|
+
return (
|
|
49
|
+
<MenuButton menuItems={actionItems} size="small">
|
|
50
|
+
<StyledSpan>{item.name}</StyledSpan>
|
|
51
|
+
</MenuButton>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
return <StyledSafeLink to={item.to}>{item.name}</StyledSafeLink>;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const renderSeparator = (item: IndexedBreadcrumbItem, totalCount: number) => {
|
|
58
|
+
if (item.index === totalCount - 1) {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return <StyledRightChevron />;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
return <Breadcrumb items={items} renderItem={renderItem} renderSeparator={renderSeparator} />;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export default ActionBreadcrumb;
|
package/src/Breadcrumb/index.ts
CHANGED
|
@@ -6,15 +6,13 @@
|
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import React from 'react';
|
|
10
|
-
import { useTranslation } from 'react-i18next';
|
|
11
9
|
import styled from '@emotion/styled';
|
|
10
|
+
import Button from '@ndla/button';
|
|
12
11
|
import { animations, colors, fonts, spacing } from '@ndla/core';
|
|
13
12
|
import { ChevronDown, FeideText, LogIn, LogOut } from '@ndla/icons/common';
|
|
14
|
-
import
|
|
15
|
-
|
|
16
|
-
import { AuthModalProps } from '../User/AuthModal';
|
|
17
|
-
import AuthModal from '../User';
|
|
13
|
+
import React from 'react';
|
|
14
|
+
import { useTranslation } from 'react-i18next';
|
|
15
|
+
import AuthModal, { AuthModalProps } from '../User/AuthModal';
|
|
18
16
|
|
|
19
17
|
const Wrapper = styled.div`
|
|
20
18
|
display: flex;
|
|
@@ -66,7 +64,7 @@ const AuthedButton = styled(Button)`
|
|
|
66
64
|
}
|
|
67
65
|
`;
|
|
68
66
|
|
|
69
|
-
const FooterAuth = ({ isAuthenticated,
|
|
67
|
+
const FooterAuth = ({ isAuthenticated, user, onAuthenticateClick, ...rest }: AuthModalProps) => {
|
|
70
68
|
const { t } = useTranslation();
|
|
71
69
|
return (
|
|
72
70
|
<Wrapper>
|
|
@@ -78,11 +76,11 @@ const FooterAuth = ({ isAuthenticated, onAuthenticateClick, authorizedRole, ...r
|
|
|
78
76
|
<AuthModal
|
|
79
77
|
{...rest}
|
|
80
78
|
isAuthenticated={isAuthenticated}
|
|
79
|
+
user={user}
|
|
81
80
|
onAuthenticateClick={onAuthenticateClick}
|
|
82
|
-
authorizedRole={authorizedRole}
|
|
83
81
|
activateButton={
|
|
84
82
|
<AuthedButton ghostPill size="medium">
|
|
85
|
-
{t('user.loggedInAsButton', { role:
|
|
83
|
+
{t('user.loggedInAsButton', { role: user?.eduPersonPrimaryAffiliation })}
|
|
86
84
|
<ChevronDown />
|
|
87
85
|
</AuthedButton>
|
|
88
86
|
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2022-present, NDLA.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the GPLv3 license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import React, { ReactNode } from 'react';
|
|
10
|
+
import styled from '@emotion/styled';
|
|
11
|
+
import { spacing, fonts, colors } from '@ndla/core';
|
|
12
|
+
|
|
13
|
+
const InfoBlockWrapper = styled.div`
|
|
14
|
+
border-bottom: 1px solid ${colors.brand.neutral7};
|
|
15
|
+
padding: ${spacing.small} 0;
|
|
16
|
+
`;
|
|
17
|
+
|
|
18
|
+
const IconWrapper = styled.div`
|
|
19
|
+
align-items: flex-start;
|
|
20
|
+
display: flex;
|
|
21
|
+
|
|
22
|
+
svg {
|
|
23
|
+
height: 25px;
|
|
24
|
+
width: 25px;
|
|
25
|
+
}
|
|
26
|
+
`;
|
|
27
|
+
|
|
28
|
+
const StyledTextWrapper = styled.div`
|
|
29
|
+
${fonts.sizes(18)}
|
|
30
|
+
`;
|
|
31
|
+
|
|
32
|
+
const TitleWrapper = styled.div`
|
|
33
|
+
display: flex;
|
|
34
|
+
|
|
35
|
+
gap: ${spacing.small};
|
|
36
|
+
`;
|
|
37
|
+
|
|
38
|
+
const StyledTitle = styled.h2`
|
|
39
|
+
${fonts.sizes('18')}
|
|
40
|
+
font-weight: 700;
|
|
41
|
+
margin: 0;
|
|
42
|
+
`;
|
|
43
|
+
|
|
44
|
+
interface InfoBlockProps {
|
|
45
|
+
icon?: ReactNode;
|
|
46
|
+
title?: string;
|
|
47
|
+
children?: ReactNode;
|
|
48
|
+
}
|
|
49
|
+
export const InfoBlock = ({ icon, title, children }: InfoBlockProps) => {
|
|
50
|
+
return (
|
|
51
|
+
<InfoBlockWrapper>
|
|
52
|
+
<TitleWrapper>
|
|
53
|
+
<IconWrapper>{icon}</IconWrapper>
|
|
54
|
+
<StyledTitle>{title}</StyledTitle>
|
|
55
|
+
</TitleWrapper>
|
|
56
|
+
<StyledTextWrapper>{children}</StyledTextWrapper>
|
|
57
|
+
</InfoBlockWrapper>
|
|
58
|
+
);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export default InfoBlock;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { InfoBlock } from './InfoBlock';
|
|
@@ -123,7 +123,7 @@ const LearningPathMenu = ({
|
|
|
123
123
|
css={css`
|
|
124
124
|
padding-left: ${spacing.small};
|
|
125
125
|
`}>
|
|
126
|
-
<Tooltip
|
|
126
|
+
<Tooltip tooltip={t('learningPath.openMenuTooltip')}>
|
|
127
127
|
<StyledToggleMenubutton type="button" onClick={() => toggleOpenState(!isOpen)}>
|
|
128
128
|
{!isOpen ? <ArrowExpandRight /> : <ArrowExpandLeft />}
|
|
129
129
|
</StyledToggleMenubutton>
|
|
@@ -11,8 +11,7 @@ import styled from '@emotion/styled';
|
|
|
11
11
|
import Button from '@ndla/button';
|
|
12
12
|
import { Feide } from '@ndla/icons/common';
|
|
13
13
|
|
|
14
|
-
import AuthModal from '../User';
|
|
15
|
-
import { AuthModalProps } from '../User/AuthModal';
|
|
14
|
+
import AuthModal, { AuthModalProps } from '../User/AuthModal';
|
|
16
15
|
|
|
17
16
|
type FeideWrapperProps = {
|
|
18
17
|
inverted?: boolean;
|
|
@@ -31,11 +30,11 @@ const StyledButton = styled(Button)<FeideWrapperProps>`
|
|
|
31
30
|
}
|
|
32
31
|
`;
|
|
33
32
|
|
|
34
|
-
|
|
33
|
+
interface Props extends AuthModalProps {
|
|
35
34
|
inverted?: boolean;
|
|
36
|
-
}
|
|
35
|
+
}
|
|
37
36
|
|
|
38
|
-
const MastheadAuthModal = ({ inverted, ...rest }: Props
|
|
37
|
+
const MastheadAuthModal = ({ inverted, ...rest }: Props) => {
|
|
39
38
|
return (
|
|
40
39
|
<AuthModal
|
|
41
40
|
{...rest}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2022-present, NDLA.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the GPLv3 license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import React, { ReactNode } from 'react';
|
|
10
|
+
import styled from '@emotion/styled';
|
|
11
|
+
import { colors, spacing } from '@ndla/core';
|
|
12
|
+
import SafeLinkButton from '@ndla/safelink';
|
|
13
|
+
import { mq, breakpoints } from '@ndla/core';
|
|
14
|
+
|
|
15
|
+
const NavigationWrapper = styled.div`
|
|
16
|
+
display: flex;
|
|
17
|
+
justify-content: flex-start;
|
|
18
|
+
margin: 0;
|
|
19
|
+
max-width: 20vw;
|
|
20
|
+
border-right: 1px solid ${colors.brand.greyLighter};
|
|
21
|
+
height: 100%;
|
|
22
|
+
${mq.range({ until: breakpoints.tabletWide })} {
|
|
23
|
+
display: none;
|
|
24
|
+
}
|
|
25
|
+
`;
|
|
26
|
+
|
|
27
|
+
const Navigation = styled.div`
|
|
28
|
+
padding: ${spacing.large};
|
|
29
|
+
`;
|
|
30
|
+
|
|
31
|
+
const NavigationElementText = styled.div`
|
|
32
|
+
color: ${colors.text.primary};
|
|
33
|
+
`;
|
|
34
|
+
|
|
35
|
+
const NavigationElement = styled(SafeLinkButton)`
|
|
36
|
+
display: flex;
|
|
37
|
+
align-items: center;
|
|
38
|
+
gap: 11px;
|
|
39
|
+
height: 30px;
|
|
40
|
+
box-shadow: none;
|
|
41
|
+
&:hover {
|
|
42
|
+
background-color: ${colors.brand.lighter};
|
|
43
|
+
border-radius: 5%;
|
|
44
|
+
svg {
|
|
45
|
+
fill: ${colors.brand.primary};
|
|
46
|
+
}
|
|
47
|
+
${NavigationElementText} {
|
|
48
|
+
color: ${colors.brand.primary};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
&:focus {
|
|
52
|
+
svg {
|
|
53
|
+
fill: ${colors.brand.primary};
|
|
54
|
+
}
|
|
55
|
+
${NavigationElementText} {
|
|
56
|
+
color: ${colors.brand.primary};
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
`;
|
|
60
|
+
|
|
61
|
+
const IconWrapper = styled.div`
|
|
62
|
+
svg {
|
|
63
|
+
fill: ${colors.text.primary};
|
|
64
|
+
height: 20px;
|
|
65
|
+
width: 20px;
|
|
66
|
+
}
|
|
67
|
+
`;
|
|
68
|
+
|
|
69
|
+
interface NavProps {
|
|
70
|
+
navElements?: {
|
|
71
|
+
icon: ReactNode;
|
|
72
|
+
url: string;
|
|
73
|
+
name: string;
|
|
74
|
+
}[];
|
|
75
|
+
}
|
|
76
|
+
export const VerticalNavigation = ({ navElements }: NavProps) => {
|
|
77
|
+
return (
|
|
78
|
+
<NavigationWrapper>
|
|
79
|
+
<Navigation>
|
|
80
|
+
{navElements?.map((element) => {
|
|
81
|
+
return (
|
|
82
|
+
<NavigationElement to={element.url}>
|
|
83
|
+
<IconWrapper>{element.icon}</IconWrapper>
|
|
84
|
+
<NavigationElementText>{element.name}</NavigationElementText>
|
|
85
|
+
</NavigationElement>
|
|
86
|
+
);
|
|
87
|
+
})}
|
|
88
|
+
</Navigation>
|
|
89
|
+
</NavigationWrapper>
|
|
90
|
+
);
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export default VerticalNavigation;
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2022-present, NDLA.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the GPLv3 license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import styled from '@emotion/styled';
|
|
10
|
+
import React, { ReactNode } from 'react';
|
|
11
|
+
import { FolderOutlined } from '@ndla/icons/contentType';
|
|
12
|
+
import { FileDocumentOutline } from '@ndla/icons/common';
|
|
13
|
+
import { fonts, spacing, colors } from '@ndla/core';
|
|
14
|
+
import { css } from '@emotion/core';
|
|
15
|
+
import { useTranslation } from 'react-i18next';
|
|
16
|
+
import SafeLink from '@ndla/safelink';
|
|
17
|
+
import { MenuButton } from '@ndla/button';
|
|
18
|
+
|
|
19
|
+
interface FolderIconWrapperProps {
|
|
20
|
+
type?: LayoutType;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const FolderIconWrapper = styled.div<FolderIconWrapperProps>`
|
|
24
|
+
display: flex;
|
|
25
|
+
border-radius: 100%;
|
|
26
|
+
padding: ${spacing.small};
|
|
27
|
+
background-color: ${colors.brand.greyLighter};
|
|
28
|
+
svg {
|
|
29
|
+
width: 18px;
|
|
30
|
+
height: 18px;
|
|
31
|
+
}
|
|
32
|
+
${(p) =>
|
|
33
|
+
p.type === 'block' &&
|
|
34
|
+
css`
|
|
35
|
+
background-color: transparent;
|
|
36
|
+
${FolderWrapper}:hover & {
|
|
37
|
+
background-color: ${colors.brand.light};
|
|
38
|
+
transition-duration 0.5s;
|
|
39
|
+
}
|
|
40
|
+
`};
|
|
41
|
+
`;
|
|
42
|
+
|
|
43
|
+
const FolderTitle = styled.h2`
|
|
44
|
+
${fonts.sizes(18)};
|
|
45
|
+
font-weight: ${fonts.weight.normal};
|
|
46
|
+
margin: 0;
|
|
47
|
+
flex: 1;
|
|
48
|
+
|
|
49
|
+
overflow: hidden;
|
|
50
|
+
text-overflow: ellipsis;
|
|
51
|
+
// Unfortunate css needed for multi-line text overflow ellipsis.
|
|
52
|
+
display: -webkit-box;
|
|
53
|
+
-webkit-line-clamp: 1;
|
|
54
|
+
line-clamp: 1;
|
|
55
|
+
-webkit-box-orient: vertical;
|
|
56
|
+
`;
|
|
57
|
+
|
|
58
|
+
const FolderWrapper = styled(SafeLink)`
|
|
59
|
+
display: flex;
|
|
60
|
+
align-items: center;
|
|
61
|
+
padding: ${spacing.small};
|
|
62
|
+
border: 1px solid ${colors.brand.light};
|
|
63
|
+
border-radius: 2px;
|
|
64
|
+
box-shadow: none;
|
|
65
|
+
text-decoration: none;
|
|
66
|
+
color: ${colors.brand.greyDark};
|
|
67
|
+
font-family: ${fonts.sans};
|
|
68
|
+
transition-duration: 0.2s;
|
|
69
|
+
gap: ${spacing.small};
|
|
70
|
+
&:hover {
|
|
71
|
+
box-shadow: 1px 1px 6px 2px rgba(9, 55, 101, 0.08);
|
|
72
|
+
transition-duration: 0.2s;
|
|
73
|
+
${FolderTitle} {
|
|
74
|
+
color: ${colors.brand.primary};
|
|
75
|
+
text-decoration: underline;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
`;
|
|
79
|
+
|
|
80
|
+
interface Props {
|
|
81
|
+
title: string;
|
|
82
|
+
subFolders?: number;
|
|
83
|
+
subResources?: number;
|
|
84
|
+
description?: string;
|
|
85
|
+
link: string;
|
|
86
|
+
type: LayoutType;
|
|
87
|
+
actionMenu?: ReactNode;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
interface IconCountProps {
|
|
91
|
+
type: 'resource' | 'folder';
|
|
92
|
+
count?: number;
|
|
93
|
+
layoutType: LayoutType;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
interface IconCountWrapperProps {
|
|
97
|
+
type: LayoutType;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const IconCountWrapper = styled.div<IconCountWrapperProps>`
|
|
101
|
+
display: flex;
|
|
102
|
+
align-items: center;
|
|
103
|
+
gap: 2px;
|
|
104
|
+
${fonts.sizes(16)};
|
|
105
|
+
${(p) =>
|
|
106
|
+
p.type === 'block' &&
|
|
107
|
+
css`
|
|
108
|
+
opacity: 0;
|
|
109
|
+
${FolderWrapper}:hover & {
|
|
110
|
+
opacity: 1;
|
|
111
|
+
}
|
|
112
|
+
`};
|
|
113
|
+
`;
|
|
114
|
+
|
|
115
|
+
const IconCount = ({ type, count, layoutType }: IconCountProps) => {
|
|
116
|
+
const Icon = type === 'resource' ? FileDocumentOutline : FolderOutlined;
|
|
117
|
+
const { t } = useTranslation();
|
|
118
|
+
if (!count) return null;
|
|
119
|
+
|
|
120
|
+
return (
|
|
121
|
+
<IconCountWrapper type={layoutType}>
|
|
122
|
+
<Icon aria-label={t(`myNdla.${type}s`)} />
|
|
123
|
+
<span>{layoutType === 'block' ? count : t(`myNdla.${type}s`, { count: 3 })}</span>
|
|
124
|
+
</IconCountWrapper>
|
|
125
|
+
);
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
type LayoutType = 'list' | 'block';
|
|
129
|
+
|
|
130
|
+
const Folder = ({ link, title, subFolders, subResources, type = 'list', actionMenu }: Props) => {
|
|
131
|
+
const { t } = useTranslation();
|
|
132
|
+
return (
|
|
133
|
+
<FolderWrapper to={link}>
|
|
134
|
+
<FolderIconWrapper type={type}>
|
|
135
|
+
<FolderOutlined aria-label={t('myNdla.folder')} />
|
|
136
|
+
</FolderIconWrapper>
|
|
137
|
+
<FolderTitle>{title}</FolderTitle>
|
|
138
|
+
<IconCount layoutType={type} type={'folder'} count={subFolders} />
|
|
139
|
+
<IconCount layoutType={type} type={'resource'} count={subResources} />
|
|
140
|
+
<MenuButton size="small" />
|
|
141
|
+
</FolderWrapper>
|
|
142
|
+
);
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
export default Folder;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2022-present, NDLA.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the GPLv3 license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import styled from '@emotion/styled';
|
|
10
|
+
import { IconButton } from '@ndla/button/src';
|
|
11
|
+
import { FolderOutlined } from '@ndla/icons/contentType';
|
|
12
|
+
import { Cross } from '@ndla/icons/action';
|
|
13
|
+
import React, { ChangeEvent, KeyboardEvent, useEffect, useRef, useState } from 'react';
|
|
14
|
+
import { useTranslation } from 'react-i18next';
|
|
15
|
+
import { colors, spacing } from '@ndla/core';
|
|
16
|
+
|
|
17
|
+
// Source: https://kovart.github.io/dashed-border-generator/
|
|
18
|
+
const borderStyle = `url("data:image/svg+xml,%3csvg width='100%25' height='100%25' xmlns='http://www.w3.org/2000/svg'%3e%3crect width='100%25' height='100%25' fill='none' stroke='${encodeURIComponent(
|
|
19
|
+
colors.brand.tertiary,
|
|
20
|
+
)}' stroke-width='2' stroke-dasharray='8%2c8' stroke-dashoffset='4' stroke-linecap='square'/%3e%3c/svg%3e")`;
|
|
21
|
+
|
|
22
|
+
const FolderInputWrapper = styled.div`
|
|
23
|
+
display: flex;
|
|
24
|
+
flex-direction: row;
|
|
25
|
+
align-items: center;
|
|
26
|
+
padding: ${spacing.small};
|
|
27
|
+
|
|
28
|
+
background-image: ${borderStyle};
|
|
29
|
+
`;
|
|
30
|
+
|
|
31
|
+
const StyledFolderIcon = styled.span`
|
|
32
|
+
display: flex;
|
|
33
|
+
padding: ${spacing.small};
|
|
34
|
+
svg {
|
|
35
|
+
color: ${colors.brand.primary};
|
|
36
|
+
height: 20px;
|
|
37
|
+
width: 20px;
|
|
38
|
+
}
|
|
39
|
+
`;
|
|
40
|
+
|
|
41
|
+
const StyledInput = styled.input`
|
|
42
|
+
color: ${colors.brand.primary};
|
|
43
|
+
outline: none;
|
|
44
|
+
border: none;
|
|
45
|
+
margin-right: auto;
|
|
46
|
+
line-height: 1.75em;
|
|
47
|
+
|
|
48
|
+
::selection {
|
|
49
|
+
background: ${colors.brand.lighter};
|
|
50
|
+
}
|
|
51
|
+
`;
|
|
52
|
+
|
|
53
|
+
interface Props {
|
|
54
|
+
onAddFolder: (name: string) => void;
|
|
55
|
+
onClose: () => void;
|
|
56
|
+
autoFocus?: boolean;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const FolderInput = ({ onAddFolder, onClose, autoFocus }: Props) => {
|
|
60
|
+
const { t } = useTranslation();
|
|
61
|
+
const newFolderText = t('treeStructure.newFolder.defaultName');
|
|
62
|
+
const [input, setInput] = useState<string>(newFolderText);
|
|
63
|
+
const [mounted, setMounted] = useState(false);
|
|
64
|
+
const inputRef = useRef<HTMLInputElement>(null);
|
|
65
|
+
|
|
66
|
+
const handleInputChange = (e: ChangeEvent<HTMLInputElement>) => {
|
|
67
|
+
setInput(e.target.value);
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const onKeydown = (e: KeyboardEvent<HTMLInputElement>) => {
|
|
71
|
+
if (e.key === 'Enter' && input) {
|
|
72
|
+
e.preventDefault();
|
|
73
|
+
onAddFolder(input);
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
useEffect(() => {
|
|
78
|
+
if (mounted && autoFocus) {
|
|
79
|
+
inputRef.current?.select();
|
|
80
|
+
} else {
|
|
81
|
+
setMounted(true);
|
|
82
|
+
}
|
|
83
|
+
}, [mounted, autoFocus]);
|
|
84
|
+
|
|
85
|
+
return (
|
|
86
|
+
<FolderInputWrapper>
|
|
87
|
+
<StyledFolderIcon>
|
|
88
|
+
<FolderOutlined />
|
|
89
|
+
</StyledFolderIcon>
|
|
90
|
+
<StyledInput
|
|
91
|
+
ref={inputRef}
|
|
92
|
+
value={input}
|
|
93
|
+
onChange={handleInputChange}
|
|
94
|
+
onKeyDown={onKeydown}
|
|
95
|
+
aria-label={newFolderText}
|
|
96
|
+
/>
|
|
97
|
+
<IconButton aria-label={t('close')} size="small" ghostPill onClick={onClose}>
|
|
98
|
+
<Cross />
|
|
99
|
+
</IconButton>
|
|
100
|
+
</FolderInputWrapper>
|
|
101
|
+
);
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
export default FolderInput;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2022-present, NDLA.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the GPLv3 license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import Folder from './Folder';
|
|
10
|
+
import FolderInput from './FolderInput';
|
|
11
|
+
export { Folder, FolderInput };
|
package/src/MyNdla/index.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
export { ResourceElement, ResourcesView, Breadcrumbs };
|
|
1
|
+
import Folder from './Resource/Folder';
|
|
2
|
+
import FolderInput from './Resource/FolderInput';
|
|
3
|
+
import { VerticalNavigation } from './Navigation';
|
|
4
|
+
export { VerticalNavigation, Folder, FolderInput };
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2022-present, NDLA.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the GPLv3 license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import styled from '@emotion/styled';
|
|
10
|
+
import React, { ReactNode } from 'react';
|
|
11
|
+
import SafeLink from '@ndla/safelink';
|
|
12
|
+
import { colors, fonts, spacing } from '@ndla/core';
|
|
13
|
+
import Image from '../Image';
|
|
14
|
+
import { CompressTagsLength, ResourceImageProps, ResourceTitle, Row, TopicList } from './resourceComponents';
|
|
15
|
+
|
|
16
|
+
interface BlockResourceProps {
|
|
17
|
+
link: string;
|
|
18
|
+
title: string;
|
|
19
|
+
resourceImage: ResourceImageProps;
|
|
20
|
+
topics: string[];
|
|
21
|
+
tags?: string[];
|
|
22
|
+
description?: string;
|
|
23
|
+
actionMenu?: ReactNode;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const BlockElementWrapper = styled(SafeLink)`
|
|
27
|
+
display: flex;
|
|
28
|
+
text-decoration: none;
|
|
29
|
+
box-shadow: none;
|
|
30
|
+
flex-direction: column;
|
|
31
|
+
max-width: 300px;
|
|
32
|
+
max-height: 240px;
|
|
33
|
+
border: 1px solid ${colors.brand.light};
|
|
34
|
+
border-radius: 2px;
|
|
35
|
+
color: ${colors.brand.greyDark};
|
|
36
|
+
`;
|
|
37
|
+
|
|
38
|
+
const BlockDescription = styled.p`
|
|
39
|
+
display: -webkit-box;
|
|
40
|
+
line-clamp: 2;
|
|
41
|
+
${fonts.sizes(16)};
|
|
42
|
+
height: 0em;
|
|
43
|
+
margin: 0;
|
|
44
|
+
overflow: hidden;
|
|
45
|
+
text-overflow: ellipsis;
|
|
46
|
+
transition: height 0.2s ease-out;
|
|
47
|
+
${() => BlockElementWrapper}:hover & {
|
|
48
|
+
// Unfortunate css needed for multi-line text overflow ellipsis.
|
|
49
|
+
height: 3.1em;
|
|
50
|
+
-webkit-line-clamp: 2;
|
|
51
|
+
line-clamp: 2;
|
|
52
|
+
-webkit-box-orient: vertical;
|
|
53
|
+
}
|
|
54
|
+
`;
|
|
55
|
+
|
|
56
|
+
const RightRow = styled(Row)`
|
|
57
|
+
justify-content: flex-end;
|
|
58
|
+
`;
|
|
59
|
+
|
|
60
|
+
const BlockInfoWrapper = styled.div`
|
|
61
|
+
display: flex;
|
|
62
|
+
flex-direction: column;
|
|
63
|
+
padding: ${spacing.small};
|
|
64
|
+
gap: ${spacing.xxsmall};
|
|
65
|
+
`;
|
|
66
|
+
|
|
67
|
+
const ImageWrapper = styled.div`
|
|
68
|
+
display: flex;
|
|
69
|
+
width: 100%;
|
|
70
|
+
overflow: hidden;
|
|
71
|
+
align-items: center;
|
|
72
|
+
div {
|
|
73
|
+
min-width: 100%;
|
|
74
|
+
}
|
|
75
|
+
img {
|
|
76
|
+
min-width: 100%;
|
|
77
|
+
}
|
|
78
|
+
`;
|
|
79
|
+
|
|
80
|
+
const BlockResource = ({ link, title, tags, resourceImage, topics, description, actionMenu }: BlockResourceProps) => {
|
|
81
|
+
return (
|
|
82
|
+
<BlockElementWrapper to={link}>
|
|
83
|
+
<ImageWrapper>
|
|
84
|
+
<Image alt={resourceImage.alt} src={resourceImage.src} />
|
|
85
|
+
</ImageWrapper>
|
|
86
|
+
<BlockInfoWrapper>
|
|
87
|
+
<div>
|
|
88
|
+
<ResourceTitle>{title}</ResourceTitle>
|
|
89
|
+
</div>
|
|
90
|
+
<TopicList topics={topics} />
|
|
91
|
+
<BlockDescription>{description}</BlockDescription>
|
|
92
|
+
<RightRow>
|
|
93
|
+
{tags && CompressTagsLength(tags)}
|
|
94
|
+
{actionMenu}
|
|
95
|
+
</RightRow>
|
|
96
|
+
</BlockInfoWrapper>
|
|
97
|
+
</BlockElementWrapper>
|
|
98
|
+
);
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
export default BlockResource;
|