@ndla/ui 45.0.13 → 45.0.14
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/Embed/ConceptEmbed.js +13 -15
- package/es/Embed/conceptComponents.js +19 -12
- package/es/Embed/index.js +2 -1
- package/es/Gloss/Gloss.js +63 -61
- package/es/index.js +1 -1
- package/lib/Embed/ConceptEmbed.d.ts +8 -1
- package/lib/Embed/ConceptEmbed.js +14 -15
- package/lib/Embed/conceptComponents.d.ts +1 -0
- package/lib/Embed/conceptComponents.js +19 -12
- package/lib/Embed/index.d.ts +1 -0
- package/lib/Embed/index.js +10 -1
- package/lib/Gloss/Gloss.d.ts +1 -1
- package/lib/Gloss/Gloss.js +63 -61
- package/lib/index.d.ts +1 -1
- package/lib/index.js +6 -0
- package/package.json +2 -2
- package/src/Embed/ConceptEmbed.stories.tsx +96 -1
- package/src/Embed/ConceptEmbed.tsx +8 -12
- package/src/Embed/conceptComponents.tsx +13 -2
- package/src/Embed/index.ts +1 -0
- package/src/Gloss/Gloss.tsx +63 -56
- package/src/index.ts +1 -0
|
@@ -19,6 +19,13 @@ const blockEmbedData: ConceptEmbedData = {
|
|
|
19
19
|
linkText: '',
|
|
20
20
|
};
|
|
21
21
|
|
|
22
|
+
const glossBlockEmbedData: ConceptEmbedData = {
|
|
23
|
+
contentId: '4942',
|
|
24
|
+
resource: 'concept',
|
|
25
|
+
type: 'block',
|
|
26
|
+
linkText: '',
|
|
27
|
+
};
|
|
28
|
+
|
|
22
29
|
const inlineEmbedData: ConceptEmbedData = {
|
|
23
30
|
contentId: '2318',
|
|
24
31
|
linkText: 'forklaring',
|
|
@@ -26,6 +33,13 @@ const inlineEmbedData: ConceptEmbedData = {
|
|
|
26
33
|
type: 'inline',
|
|
27
34
|
};
|
|
28
35
|
|
|
36
|
+
const glossInlineEmbedData: ConceptEmbedData = {
|
|
37
|
+
contentId: '23',
|
|
38
|
+
linkText: 'glose',
|
|
39
|
+
resource: 'concept',
|
|
40
|
+
type: 'inline',
|
|
41
|
+
};
|
|
42
|
+
|
|
29
43
|
const conceptMetaData: ConceptData['concept'] = {
|
|
30
44
|
id: 110,
|
|
31
45
|
revision: 16,
|
|
@@ -68,7 +82,68 @@ const conceptMetaData: ConceptData['concept'] = {
|
|
|
68
82
|
'<ndlaembed data-resource="image" data-resource_id="52863" data-alt="Eksempel på hvordan borevæsken kan trenge ut i formasjonen fra borehullet og skade formasjonens permeabilitet. Illustrasjon." data-size="full" data-align="" data-url="https://api.test.ndla.no/image-api/v2/images/52863"></ndlaembed>',
|
|
69
83
|
language: 'nb',
|
|
70
84
|
},
|
|
71
|
-
conceptType: '
|
|
85
|
+
conceptType: 'concept',
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const glossMetaData: ConceptData['concept'] = {
|
|
89
|
+
id: 4942,
|
|
90
|
+
revision: 6,
|
|
91
|
+
title: {
|
|
92
|
+
title: 'Ma Hong',
|
|
93
|
+
language: 'nb',
|
|
94
|
+
},
|
|
95
|
+
content: {
|
|
96
|
+
content: 'Hei',
|
|
97
|
+
language: 'nb',
|
|
98
|
+
},
|
|
99
|
+
copyright: {
|
|
100
|
+
creators: [],
|
|
101
|
+
processors: [],
|
|
102
|
+
rightsholders: [],
|
|
103
|
+
processed: false,
|
|
104
|
+
},
|
|
105
|
+
source: '',
|
|
106
|
+
metaImage: {
|
|
107
|
+
url: '',
|
|
108
|
+
alt: '',
|
|
109
|
+
language: 'und',
|
|
110
|
+
},
|
|
111
|
+
created: '2023-07-19T09:30:40.000Z',
|
|
112
|
+
updated: '2023-09-19T17:13:56.573Z',
|
|
113
|
+
updatedBy: ['XxnkdI7rApMl58MeG3p4g4B8', 'hd5ZL5Lm4kKkumWgN2gjy9wx'],
|
|
114
|
+
supportedLanguages: ['nb'],
|
|
115
|
+
articleIds: [],
|
|
116
|
+
status: {
|
|
117
|
+
current: 'IN_PROGRESS',
|
|
118
|
+
other: [],
|
|
119
|
+
},
|
|
120
|
+
responsible: {
|
|
121
|
+
responsibleId: 'XxnkdI7rApMl58MeG3p4g4B8',
|
|
122
|
+
lastUpdated: '2023-07-19T09:30:40.000Z',
|
|
123
|
+
},
|
|
124
|
+
conceptType: 'gloss',
|
|
125
|
+
glossData: {
|
|
126
|
+
gloss: '马红',
|
|
127
|
+
wordClass: 'personal-pronoun',
|
|
128
|
+
originalLanguage: 'zh',
|
|
129
|
+
transcriptions: {},
|
|
130
|
+
examples: [
|
|
131
|
+
[
|
|
132
|
+
{
|
|
133
|
+
example: '我叫马红',
|
|
134
|
+
language: 'zh',
|
|
135
|
+
transcriptions: {
|
|
136
|
+
pinyin: 'wo jiao ma hong ',
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
example: 'Jeg heter ma hong',
|
|
141
|
+
language: 'nb',
|
|
142
|
+
transcriptions: {},
|
|
143
|
+
},
|
|
144
|
+
],
|
|
145
|
+
],
|
|
146
|
+
},
|
|
72
147
|
};
|
|
73
148
|
|
|
74
149
|
const visualElementData: ConceptData['visualElement'] = {
|
|
@@ -141,6 +216,10 @@ const blockMetaData: ConceptData = {
|
|
|
141
216
|
visualElement: visualElementData,
|
|
142
217
|
};
|
|
143
218
|
|
|
219
|
+
const glossBlockData: ConceptData = {
|
|
220
|
+
concept: glossMetaData,
|
|
221
|
+
};
|
|
222
|
+
|
|
144
223
|
const meta: Meta<typeof ConceptEmbed> = {
|
|
145
224
|
title: 'Components/Embeds/ConceptEmbed',
|
|
146
225
|
component: ConceptEmbed,
|
|
@@ -177,6 +256,11 @@ export const Block: StoryObj<typeof ConceptEmbed> = {
|
|
|
177
256
|
},
|
|
178
257
|
},
|
|
179
258
|
};
|
|
259
|
+
export const GlossBlock: StoryObj<typeof ConceptEmbed> = {
|
|
260
|
+
args: {
|
|
261
|
+
embed: { resource: 'concept', status: 'success', embedData: glossBlockEmbedData, data: glossBlockData },
|
|
262
|
+
},
|
|
263
|
+
};
|
|
180
264
|
|
|
181
265
|
export const BlockFailed: StoryObj<typeof ConceptEmbed> = {
|
|
182
266
|
args: {
|
|
@@ -201,6 +285,17 @@ export const Inline: StoryObj<typeof ConceptEmbed> = {
|
|
|
201
285
|
},
|
|
202
286
|
};
|
|
203
287
|
|
|
288
|
+
export const GlossInline: StoryObj<typeof ConceptEmbed> = {
|
|
289
|
+
args: {
|
|
290
|
+
embed: {
|
|
291
|
+
resource: 'concept',
|
|
292
|
+
status: 'success',
|
|
293
|
+
embedData: glossInlineEmbedData,
|
|
294
|
+
data: glossBlockData,
|
|
295
|
+
},
|
|
296
|
+
},
|
|
297
|
+
};
|
|
298
|
+
|
|
204
299
|
export const InlineFailed: StoryObj<typeof ConceptEmbed> = {
|
|
205
300
|
args: {
|
|
206
301
|
heartButton: StoryFavoriteButton,
|
|
@@ -14,7 +14,7 @@ import { Root, Trigger, Content, Anchor, Close, Portal } from '@radix-ui/react-p
|
|
|
14
14
|
import { IconButtonV2 } from '@ndla/button';
|
|
15
15
|
import { Cross } from '@ndla/icons/action';
|
|
16
16
|
import { breakpoints, colors, mq, spacing } from '@ndla/core';
|
|
17
|
-
import {
|
|
17
|
+
import { ConceptMetaData } from '@ndla/types-embed';
|
|
18
18
|
import Tooltip from '@ndla/tooltip';
|
|
19
19
|
import { COPYRIGHTED } from '@ndla/licenses';
|
|
20
20
|
import { Notion as UINotion } from '../Notion';
|
|
@@ -26,11 +26,6 @@ import EmbedErrorPlaceholder from './EmbedErrorPlaceholder';
|
|
|
26
26
|
import { HeartButtonType } from './types';
|
|
27
27
|
import { Gloss } from '../Gloss';
|
|
28
28
|
|
|
29
|
-
const BottomBorder = styled.div`
|
|
30
|
-
margin-top: ${spacing.normal};
|
|
31
|
-
border-bottom: 1px solid ${colors.brand.greyLight};
|
|
32
|
-
`;
|
|
33
|
-
|
|
34
29
|
interface PopoverPosition {
|
|
35
30
|
top?: number;
|
|
36
31
|
}
|
|
@@ -158,8 +153,9 @@ export const ConceptEmbed = ({ embed, fullWidth, heartButton: HeartButton }: Pro
|
|
|
158
153
|
};
|
|
159
154
|
|
|
160
155
|
interface InlineConceptProps extends ConceptNotionData {
|
|
161
|
-
linkText:
|
|
156
|
+
linkText: ReactNode;
|
|
162
157
|
heartButton?: HeartButtonType;
|
|
158
|
+
headerButtons?: ReactNode;
|
|
163
159
|
conceptHeartButton?: ReactNode;
|
|
164
160
|
}
|
|
165
161
|
|
|
@@ -221,7 +217,7 @@ const getModalPosition = (anchor: HTMLElement) => {
|
|
|
221
217
|
return anchorPos.top - (articlePos?.top || -window.scrollY);
|
|
222
218
|
};
|
|
223
219
|
|
|
224
|
-
const InlineConcept = ({
|
|
220
|
+
export const InlineConcept = ({
|
|
225
221
|
title,
|
|
226
222
|
content,
|
|
227
223
|
copyright,
|
|
@@ -232,6 +228,7 @@ const InlineConcept = ({
|
|
|
232
228
|
conceptHeartButton,
|
|
233
229
|
glossData,
|
|
234
230
|
conceptType,
|
|
231
|
+
headerButtons,
|
|
235
232
|
}: InlineConceptProps) => {
|
|
236
233
|
const { t } = useTranslation();
|
|
237
234
|
const anchorRef = useRef<HTMLDivElement>(null);
|
|
@@ -271,6 +268,7 @@ const InlineConcept = ({
|
|
|
271
268
|
visualElement={visualElement}
|
|
272
269
|
inPopover
|
|
273
270
|
heartButton={heartButton}
|
|
271
|
+
headerButtons={headerButtons}
|
|
274
272
|
conceptHeartButton={conceptHeartButton}
|
|
275
273
|
closeButton={
|
|
276
274
|
<Close asChild>
|
|
@@ -399,7 +397,7 @@ export const BlockConcept = ({
|
|
|
399
397
|
/>
|
|
400
398
|
) : (
|
|
401
399
|
<Gloss
|
|
402
|
-
glossData={glossData
|
|
400
|
+
glossData={glossData}
|
|
403
401
|
title={title}
|
|
404
402
|
audio={
|
|
405
403
|
visualElement?.status === 'success' && visualElement.resource === 'audio'
|
|
@@ -408,12 +406,10 @@ export const BlockConcept = ({
|
|
|
408
406
|
}
|
|
409
407
|
/>
|
|
410
408
|
)}
|
|
411
|
-
{copyright && conceptType === 'concept'
|
|
409
|
+
{copyright && conceptType === 'concept' && (
|
|
412
410
|
<EmbedByline copyright={copyright} bottomRounded topRounded type={conceptType as ConceptType}>
|
|
413
411
|
{copyright.license?.license.toLowerCase() !== COPYRIGHTED && conceptHeartButton}
|
|
414
412
|
</EmbedByline>
|
|
415
|
-
) : (
|
|
416
|
-
<BottomBorder />
|
|
417
413
|
)}
|
|
418
414
|
</Figure>
|
|
419
415
|
</Root>
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { forwardRef, ReactNode, RefAttributes } from 'react';
|
|
10
|
-
import {
|
|
10
|
+
import { ConceptData, ConceptVisualElementMeta } from '@ndla/types-embed';
|
|
11
11
|
import { useTranslation } from 'react-i18next';
|
|
12
12
|
import { css } from '@emotion/react';
|
|
13
13
|
import { breakpoints, colors, fonts, misc, mq, spacing } from '@ndla/core';
|
|
@@ -46,6 +46,7 @@ interface ConceptNotionProps extends RefAttributes<HTMLDivElement>, ConceptNotio
|
|
|
46
46
|
inPopover?: boolean;
|
|
47
47
|
tags?: string[];
|
|
48
48
|
subjects?: string[];
|
|
49
|
+
headerButtons?: ReactNode;
|
|
49
50
|
heartButton?: HeartButtonType;
|
|
50
51
|
conceptHeartButton?: ReactNode;
|
|
51
52
|
}
|
|
@@ -125,6 +126,12 @@ const StyledNotionDialogContent = styled(NotionDialogContent)`
|
|
|
125
126
|
}
|
|
126
127
|
`;
|
|
127
128
|
|
|
129
|
+
const ButtonWrapper = styled.div`
|
|
130
|
+
display: flex;
|
|
131
|
+
gap: ${spacing.xsmall};
|
|
132
|
+
align-items: center;
|
|
133
|
+
`;
|
|
134
|
+
|
|
128
135
|
const StyledList = styled.ul`
|
|
129
136
|
display: flex;
|
|
130
137
|
gap: ${spacing.small};
|
|
@@ -158,6 +165,7 @@ export const ConceptNotionV2 = forwardRef<HTMLDivElement, ConceptNotionProps>(
|
|
|
158
165
|
conceptHeartButton,
|
|
159
166
|
conceptType,
|
|
160
167
|
glossData,
|
|
168
|
+
headerButtons,
|
|
161
169
|
...rest
|
|
162
170
|
},
|
|
163
171
|
ref,
|
|
@@ -171,7 +179,10 @@ export const ConceptNotionV2 = forwardRef<HTMLDivElement, ConceptNotionProps>(
|
|
|
171
179
|
<h1>
|
|
172
180
|
{title.title} {<small>{t(`searchPage.resultType.${conceptType}`)}</small>}
|
|
173
181
|
</h1>
|
|
174
|
-
|
|
182
|
+
<ButtonWrapper>
|
|
183
|
+
{headerButtons}
|
|
184
|
+
{closeButton}
|
|
185
|
+
</ButtonWrapper>
|
|
175
186
|
</NotionHeader>
|
|
176
187
|
{conceptType !== 'gloss' ? (
|
|
177
188
|
<>
|
package/src/Embed/index.ts
CHANGED
|
@@ -19,4 +19,5 @@ export { default as ConceptEmbed } from './ConceptEmbed';
|
|
|
19
19
|
export { ConceptNotionV2 } from './conceptComponents';
|
|
20
20
|
export { default as ConceptListEmbed } from './ConceptListEmbed';
|
|
21
21
|
export { default as UnknownEmbed } from './UnknownEmbed';
|
|
22
|
+
export { InlineConcept } from './ConceptEmbed';
|
|
22
23
|
export type { HeartButtonType } from './types';
|
package/src/Gloss/Gloss.tsx
CHANGED
|
@@ -24,7 +24,7 @@ export interface Props {
|
|
|
24
24
|
title: string;
|
|
25
25
|
language: string;
|
|
26
26
|
};
|
|
27
|
-
glossData
|
|
27
|
+
glossData?: {
|
|
28
28
|
gloss: string;
|
|
29
29
|
wordClass?: string;
|
|
30
30
|
originalLanguage: string;
|
|
@@ -98,63 +98,70 @@ const Gloss = ({ title, glossData, audio }: Props) => {
|
|
|
98
98
|
|
|
99
99
|
return (
|
|
100
100
|
<>
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
<
|
|
104
|
-
<
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
<
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
<
|
|
138
|
-
{
|
|
139
|
-
<div key={
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
{translation.transcriptions
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
{translation.transcriptions
|
|
149
|
-
|
|
150
|
-
|
|
101
|
+
{glossData && (
|
|
102
|
+
<>
|
|
103
|
+
<Container>
|
|
104
|
+
<Wrapper>
|
|
105
|
+
<GlossContainer>
|
|
106
|
+
<GlossSpan lang={glossData.originalLanguage}>{glossData.gloss}</GlossSpan>
|
|
107
|
+
{glossData.transcriptions.traditional && (
|
|
108
|
+
<span
|
|
109
|
+
key={t('gloss.transcriptions.traditional')}
|
|
110
|
+
aria-label={t('gloss.transcriptions.traditional')}
|
|
111
|
+
lang={glossData.originalLanguage}
|
|
112
|
+
>
|
|
113
|
+
{glossData.transcriptions.traditional}
|
|
114
|
+
</span>
|
|
115
|
+
)}
|
|
116
|
+
{glossData.transcriptions.pinyin && (
|
|
117
|
+
<span
|
|
118
|
+
key={t('gloss.transcriptions.pinyin')}
|
|
119
|
+
aria-label={t('gloss.transcriptions.pinyin')}
|
|
120
|
+
lang={glossData.originalLanguage}
|
|
121
|
+
>
|
|
122
|
+
{glossData.transcriptions.pinyin}
|
|
123
|
+
</span>
|
|
124
|
+
)}
|
|
125
|
+
{glossData.wordClass && (
|
|
126
|
+
<TypeSpan aria-label={t('gloss.wordClass')}>{t(`wordClass.${glossData.wordClass}`)}</TypeSpan>
|
|
127
|
+
)}
|
|
128
|
+
</GlossContainer>
|
|
129
|
+
{audio?.src && <SpeechControl src={audio.src} title={audio.title}></SpeechControl>}
|
|
130
|
+
</Wrapper>
|
|
131
|
+
<span>{title.title}</span>
|
|
132
|
+
</Container>
|
|
133
|
+
{glossData.examples && glossData.examples.length > 0 && (
|
|
134
|
+
<AccordionRoot type="single" collapsible>
|
|
135
|
+
<AccordionItem value="1">
|
|
136
|
+
<StyledAccordionHeader>{t('gloss.examples')}</StyledAccordionHeader>
|
|
137
|
+
<StyledAccordionContent>
|
|
138
|
+
{glossData.examples.map((example, index) => (
|
|
139
|
+
<div key={index}>
|
|
140
|
+
{example.map((translation, innerIndex) => (
|
|
141
|
+
<div key={`${index}_${innerIndex}`}>
|
|
142
|
+
<TranslatedText data-first={innerIndex === 0}>{translation.example}</TranslatedText>
|
|
143
|
+
{translation.transcriptions.pinyin && (
|
|
144
|
+
<TranslatedText key={t('gloss.transcriptions.pinyin')} lang={glossData.originalLanguage}>
|
|
145
|
+
{translation.transcriptions?.pinyin}
|
|
146
|
+
</TranslatedText>
|
|
147
|
+
)}
|
|
148
|
+
{translation.transcriptions.traditional && (
|
|
149
|
+
<TranslatedText
|
|
150
|
+
key={t('gloss.transcriptions.traditional')}
|
|
151
|
+
lang={glossData.originalLanguage}
|
|
152
|
+
>
|
|
153
|
+
{translation.transcriptions?.traditional}
|
|
154
|
+
</TranslatedText>
|
|
155
|
+
)}
|
|
156
|
+
</div>
|
|
157
|
+
))}
|
|
151
158
|
</div>
|
|
152
159
|
))}
|
|
153
|
-
</
|
|
154
|
-
|
|
155
|
-
</
|
|
156
|
-
|
|
157
|
-
|
|
160
|
+
</StyledAccordionContent>
|
|
161
|
+
</AccordionItem>
|
|
162
|
+
</AccordionRoot>
|
|
163
|
+
)}
|
|
164
|
+
</>
|
|
158
165
|
)}
|
|
159
166
|
</>
|
|
160
167
|
);
|