diff --git a/newIDE/app/src/Course/TextBasedCourseChapterCalloutBlock.js b/newIDE/app/src/Course/TextBasedCourseChapterCalloutBlock.js
new file mode 100644
index 000000000000..b017630070fc
--- /dev/null
+++ b/newIDE/app/src/Course/TextBasedCourseChapterCalloutBlock.js
@@ -0,0 +1,69 @@
+// @flow
+
+import * as React from 'react';
+import GDevelopThemeContext from '../UI/Theme/GDevelopThemeContext';
+import { MarkdownText } from '../UI/MarkdownText';
+import { Trans } from '@lingui/macro';
+import ReactMarkdown from 'react-markdown';
+
+type Props = {|
+ calloutType?: 'info' | 'warning' | 'tip' | 'note',
+ title: string,
+ text: string,
+ children?: React.Node,
+|};
+
+const TextBasedCourseChapterCalloutBlock = ({
+ title,
+ text,
+ calloutType = 'info',
+ children,
+}: Props) => {
+ const gdevelopTheme = React.useContext(GDevelopThemeContext);
+
+ const isDarkMode = gdevelopTheme.palette.type === 'dark';
+ const backgroundColor = isDarkMode ? '#0f172a' : '#f3f4f6';
+ const borderColor = isDarkMode
+ ? 'rgba(255, 255, 255, 0.08)'
+ : 'rgba(15, 23, 42, 0.15)';
+
+ const getIcon = (type: string): string => {
+ switch (type) {
+ case 'info':
+ return 'ℹ️';
+ case 'warning':
+ return '⚠️';
+ case 'tip':
+ return '💡';
+ case 'note':
+ return '📝';
+ default:
+ return '📝';
+ }
+ };
+
+ return (
+
+
{getIcon(calloutType)}
+
+
+ );
+};
+
+export default TextBasedCourseChapterCalloutBlock;
diff --git a/newIDE/app/src/Course/TextBasedCourseChapterItems.js b/newIDE/app/src/Course/TextBasedCourseChapterItems.js
index 7d4cfcdbf8bf..6aa52002d1b4 100644
--- a/newIDE/app/src/Course/TextBasedCourseChapterItems.js
+++ b/newIDE/app/src/Course/TextBasedCourseChapterItems.js
@@ -8,6 +8,7 @@ import type {
TextBasedCourseChapterVideoItem as TextBasedCourseChapterVideoItemType,
TextBasedCourseChapterCodeItem as TextBasedCourseChapterCodeItemType,
TextBasedCourseChapterTableItem as TextBasedCourseChapterTableItemType,
+ TextBasedCourseChapterCalloutItem as TextBasedCourseChapterCalloutItemType,
} from '../Utils/GDevelopServices/Asset';
import GDevelopThemeContext from '../UI/Theme/GDevelopThemeContext';
import { MarkdownText } from '../UI/MarkdownText';
@@ -16,6 +17,7 @@ import TextBasedCourseChapterTaskItem from './TextBasedCourseChapterTaskItem';
import { ColumnStackLayout } from '../UI/Layout';
import { Column, Line } from '../UI/Grid';
import TextBasedCourseChapterCodeBlock from './TextBasedCourseChapterCodeBlock';
+import TextBasedCourseChapterCalloutBlock from './TextBasedCourseChapterCalloutBlock';
import TextBasedCourseChapterTable from './TextBasedCourseChapterTable';
const styles = {
@@ -34,6 +36,7 @@ type Props = {|
| TextBasedCourseChapterImageItemType
| TextBasedCourseChapterVideoItemType
| TextBasedCourseChapterCodeItemType
+ | TextBasedCourseChapterCalloutItemType
| TextBasedCourseChapterTableItemType
>
| Array<
@@ -41,6 +44,7 @@ type Props = {|
| TextBasedCourseChapterImageItemType
| TextBasedCourseChapterVideoItemType
| TextBasedCourseChapterCodeItemType
+ | TextBasedCourseChapterCalloutItemType
| TextBasedCourseChapterTableItemType
>,
|};
@@ -109,6 +113,16 @@ const TextBasedCourseChapterItems = ({
/>
);
}
+ if (item.type === 'callout') {
+ return (
+
+ );
+ }
if (item.type === 'table') {
return (
,
+ code: ({ node, ...props }) => (
+
+ ),
});
type Props = {|
diff --git a/newIDE/app/src/Utils/GDevelopServices/Asset.js b/newIDE/app/src/Utils/GDevelopServices/Asset.js
index e9e6a62e2f5e..1314fc7c6ae5 100644
--- a/newIDE/app/src/Utils/GDevelopServices/Asset.js
+++ b/newIDE/app/src/Utils/GDevelopServices/Asset.js
@@ -258,6 +258,13 @@ export type TextBasedCourseChapterCodeItem = {|
language?: string,
|};
+export type TextBasedCourseChapterCalloutItem = {|
+ type: 'callout',
+ calloutType?: 'info' | 'warning' | 'tip' | 'note',
+ title: string,
+ text: string,
+|};
+
export type TextBasedCourseChapterTableItem = {|
type: 'table',
header?: Array,
@@ -272,6 +279,7 @@ export type TextBasedCourseChapterTaskItem = {|
| TextBasedCourseChapterImageItem
| TextBasedCourseChapterVideoItem
| TextBasedCourseChapterCodeItem
+ | TextBasedCourseChapterCalloutItem
| TextBasedCourseChapterTableItem
>,
answer?: {
@@ -280,6 +288,7 @@ export type TextBasedCourseChapterTaskItem = {|
| TextBasedCourseChapterImageItem
| TextBasedCourseChapterVideoItem
| TextBasedCourseChapterCodeItem
+ | TextBasedCourseChapterCalloutItem
| TextBasedCourseChapterTableItem
>,
},
@@ -298,6 +307,7 @@ export type UnlockedTextBasedCourseChapter = {|
| TextBasedCourseChapterTaskItem
| TextBasedCourseChapterVideoItem
| TextBasedCourseChapterCodeItem
+ | TextBasedCourseChapterCalloutItem
| TextBasedCourseChapterTableItem
>,
|};
diff --git a/newIDE/app/src/fixtures/GDevelopServicesTestData/index.js b/newIDE/app/src/fixtures/GDevelopServicesTestData/index.js
index 06c204c1742d..107438927a6f 100644
--- a/newIDE/app/src/fixtures/GDevelopServicesTestData/index.js
+++ b/newIDE/app/src/fixtures/GDevelopServicesTestData/index.js
@@ -3224,6 +3224,27 @@ export const textBasedCourseChapter: TextBasedCourseChapter = {
shortTitle: 'Introduction',
};
+export const textBasedCourseChapterWithCallout: TextBasedCourseChapter = {
+ title: 'test',
+ templates: [],
+ items: [
+ {
+ type: 'text',
+ text:
+ "Let's explore how JavaScript events can control objects in your game.",
+ },
+ {
+ type: 'callout',
+ calloutType: 'info',
+ title: 'title callout',
+ text:
+ '3 Ceci est un encaddré **informatif**. Il utilise les couleurs `blue` par défaut. Il est parfait pour fournir des détails supplémentaires ou des précisions techniques. Les blocs de `code` sont également bien formatés.',
+ },
+ ],
+ id: 'callout javascript',
+ shortTitle: 'callout javascript',
+};
+
export const textBasedCourseChapterWithCode: TextBasedCourseChapter = {
title: 'Scripting Basics',
templates: [],
@@ -3270,11 +3291,19 @@ export const textBasedCourseChapterWithTables: TextBasedCourseChapter = {
type: 'table',
header: ['Stat', 'Enemy', 'Player'],
rows: [
+ ['>', '>=', 'right bugged'],
+ ['\\>', '\\>=', 'right escaped'],
+ ['<', '<=', 'left ok'],
+ ['\\<', '\\<=', 'left escaped'],
+ ['`code1`', '``code2``', '```code3```'],
['Health', '120', '100'],
- ['Damage', '12', '18'],
['Move speed', '160 px/s', '200 px/s'],
],
},
+ {
+ type: 'text',
+ text: ' `window`, ``console.log("hello");``, ```const test = 1;``` ',
+ },
{
type: 'text',
text:
diff --git a/newIDE/app/src/stories/componentStories/Course/TextBasedCourseChapterCalloutBlock.stories.js b/newIDE/app/src/stories/componentStories/Course/TextBasedCourseChapterCalloutBlock.stories.js
new file mode 100644
index 000000000000..547cc44f3136
--- /dev/null
+++ b/newIDE/app/src/stories/componentStories/Course/TextBasedCourseChapterCalloutBlock.stories.js
@@ -0,0 +1,20 @@
+// @flow
+import * as React from 'react';
+import TextBasedCourseChapterCallout from '../../../Course/TextBasedCourseChapterCalloutBlock';
+import paperDecorator from '../../PaperDecorator';
+
+export default {
+ title: 'Course/TextBasedCourseChapterCallout',
+ component: TextBasedCourseChapterCallout,
+ decorators: [paperDecorator],
+};
+
+export const Info = () => (
+
+);
diff --git a/newIDE/app/src/stories/componentStories/Course/TextBasedCourseChapterView.stories.js b/newIDE/app/src/stories/componentStories/Course/TextBasedCourseChapterView.stories.js
index ba882e6762ee..ae6af76e8f9f 100644
--- a/newIDE/app/src/stories/componentStories/Course/TextBasedCourseChapterView.stories.js
+++ b/newIDE/app/src/stories/componentStories/Course/TextBasedCourseChapterView.stories.js
@@ -9,6 +9,7 @@ import {
textBasedCourseChapter,
textBasedCourseChapterWithCode,
textBasedCourseChapterWithTables,
+ textBasedCourseChapterWithCallout,
} from '../../../fixtures/GDevelopServicesTestData';
export default {
@@ -61,3 +62,18 @@ export const Chapter3 = () => {
/>
);
};
+
+export const Chapter4 = () => {
+ return (
+ action('onClickUnlock')()}
+ />
+ );
+};