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)}
+
+
{title}
+ + +
+
+ ); +}; + +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')()} + /> + ); +};