diff --git a/composeApp/src/commonMain/kotlin/ui/screen/home/composable/CourseCard.kt b/composeApp/src/commonMain/kotlin/ui/screen/home/composable/CourseCard.kt index 056322d9..7c284d00 100644 --- a/composeApp/src/commonMain/kotlin/ui/screen/home/composable/CourseCard.kt +++ b/composeApp/src/commonMain/kotlin/ui/screen/home/composable/CourseCard.kt @@ -39,7 +39,7 @@ fun CourseCard( imageUrl = course.imageUrl, onClick = onCourseClick ) - Spacer(Modifier.height(12.dp)) + Spacer(Modifier.height(16.dp)) Title( modifier = Modifier.padding(horizontal = 16.dp), text = course.name, @@ -50,7 +50,7 @@ fun CourseCard( modifier = Modifier.padding(horizontal = 16.dp), text = course.tagline ) - Spacer(Modifier.height(12.dp)) + Spacer(Modifier.height(16.dp)) } } } @@ -65,7 +65,7 @@ private fun Banner( KamelImage( modifier = modifier .fillMaxWidth() - .height(160.dp), + .height(148.dp), contentScale = ContentScale.FillWidth, resource = asyncPainterResource(imageUrl), contentDescription = null diff --git a/server/src/main/kotlin/ivy/learn/data/cms/TopicsContent.kt b/server/src/main/kotlin/ivy/learn/data/cms/TopicsContent.kt index eb43e125..07745225 100644 --- a/server/src/main/kotlin/ivy/learn/data/cms/TopicsContent.kt +++ b/server/src/main/kotlin/ivy/learn/data/cms/TopicsContent.kt @@ -1,10 +1,20 @@ package ivy.learn.data.cms -import ivy.learn.data.cms.course.GeneralProgramming +import ivy.learn.data.cms.course.programming.* import ivy.learn.data.cms.dsl.TopicsDsl object TopicsContent : TopicsDsl({ - topic("General Programming") { - course(GeneralProgramming) + topic("Programming") { + course(ProgrammingBasics) + course(ProgrammingFundamentals) + course(DataStructures) + course(FunctionalProgramming) + course(ObjectOrientedProgramming) + } + topic("Kotlin") { + + } + topic("Compose") { + } }) \ No newline at end of file diff --git a/server/src/main/kotlin/ivy/learn/data/cms/course/CoursesContent.kt b/server/src/main/kotlin/ivy/learn/data/cms/course/CoursesContent.kt index 9299ff31..95489b47 100644 --- a/server/src/main/kotlin/ivy/learn/data/cms/course/CoursesContent.kt +++ b/server/src/main/kotlin/ivy/learn/data/cms/course/CoursesContent.kt @@ -1,7 +1,12 @@ package ivy.learn.data.cms.course +import ivy.learn.data.cms.course.programming.* import ivy.learn.data.cms.dsl.CoursesDsl object CoursesContent : CoursesDsl({ - course(GeneralProgramming) + course(ProgrammingBasics) + course(ProgrammingFundamentals) + course(DataStructures) + course(FunctionalProgramming) + course(ObjectOrientedProgramming) }) \ No newline at end of file diff --git a/server/src/main/kotlin/ivy/learn/data/cms/course/GeneralProgramming.kt b/server/src/main/kotlin/ivy/learn/data/cms/course/GeneralProgramming.kt deleted file mode 100644 index 5c2e9847..00000000 --- a/server/src/main/kotlin/ivy/learn/data/cms/course/GeneralProgramming.kt +++ /dev/null @@ -1,14 +0,0 @@ -package ivy.learn.data.cms.course - -import ivy.learn.data.cms.dsl.CourseDsl - -object GeneralProgramming : CourseDsl({ - name = "General Programming" - tagline = "Learn the basics of programming" - imageUrl = "tbd" - lesson( - name = "Programming Fundamentals 101", - tagline = "Learn the basics of programming", - imageUrl = "tbd" - ) -}) \ No newline at end of file diff --git a/server/src/main/kotlin/ivy/learn/data/cms/course/programming/DataStructures.kt b/server/src/main/kotlin/ivy/learn/data/cms/course/programming/DataStructures.kt new file mode 100644 index 00000000..67212870 --- /dev/null +++ b/server/src/main/kotlin/ivy/learn/data/cms/course/programming/DataStructures.kt @@ -0,0 +1,71 @@ +package ivy.learn.data.cms.course.programming + +import ivy.learn.data.cms.dsl.CourseDsl +import ivy.learn.data.cms.dsl.CourseImageUrl +import ivy.learn.data.cms.dsl.LessonImageUrl + +object DataStructures : CourseDsl({ + name = "Data Structures" + tagline = "Lists, Sets, Maps, Stacks, Trees and more." + imageUrl = CourseImageUrl + lesson( + name = "Arrays", + tagline = "The simplest data structure.", + imageUrl = LessonImageUrl + ) + lesson( + name = "Lists", + tagline = "Arrays with superpowers. Dynamic sizing.", + imageUrl = LessonImageUrl + ) + lesson( + name = "Linked Lists", + tagline = "A different take on lists. Pointers and nodes.", + imageUrl = LessonImageUrl + ) + lesson( + name = "Sets", + tagline = "Unique elements. No duplicates.", + imageUrl = LessonImageUrl + ) + lesson( + name = "Maps", + tagline = "Key-Value pairs. Associative arrays.", + imageUrl = LessonImageUrl + ) + lesson( + name = "Stacks", + tagline = "LIFO: Last In, First Out.", + imageUrl = LessonImageUrl + ) + lesson( + name = "Queues", + tagline = "FIFO: First In, First Out.", + imageUrl = LessonImageUrl + ) + lesson( + name = "Trees", + tagline = "Hierarchical data structures.", + imageUrl = LessonImageUrl + ) + lesson( + name = "Graphs", + tagline = "Networks of nodes and edges.", + imageUrl = LessonImageUrl + ) + lesson( + name = "Heaps", + tagline = "Priority Queues. Efficiently find the max or min.", + imageUrl = LessonImageUrl + ) + lesson( + name = "Tries", + tagline = "Prefix Trees. Efficient string search.", + imageUrl = LessonImageUrl + ) + lesson( + name = "Hash Tables", + tagline = "Fast lookups. Key-Value pairs.", + imageUrl = LessonImageUrl + ) +}) \ No newline at end of file diff --git a/server/src/main/kotlin/ivy/learn/data/cms/course/programming/FunctionalProgramming.kt b/server/src/main/kotlin/ivy/learn/data/cms/course/programming/FunctionalProgramming.kt new file mode 100644 index 00000000..6d84d34b --- /dev/null +++ b/server/src/main/kotlin/ivy/learn/data/cms/course/programming/FunctionalProgramming.kt @@ -0,0 +1,46 @@ +package ivy.learn.data.cms.course.programming + +import ivy.learn.data.cms.dsl.CourseDsl +import ivy.learn.data.cms.dsl.CourseImageUrl +import ivy.learn.data.cms.dsl.LessonImageUrl + +object FunctionalProgramming : CourseDsl({ + name = "Functional Programming (FP)" + tagline = "Programming with mathematical functions. Pure, declarative and powerful." + imageUrl = CourseImageUrl + lesson( + name = "What is a function?", + tagline = "A mathematical relation between a set of inputs and a set of outputs.", + imageUrl = LessonImageUrl + ) + lesson( + name = "Types of functions", + tagline = "Partial, total, pure. Learn these important distinctions.", + imageUrl = LessonImageUrl + ) + lesson( + name = "Higher order functions", + tagline = "Functions that take functions as arguments or return functions.", + imageUrl = LessonImageUrl + ) + lesson( + name = "Recursion", + tagline = "Functions that call themselves. The power of self-reference.", + imageUrl = LessonImageUrl + ) + lesson( + name = "Immutability", + tagline = "Values that never change. The key to functional programming.", + imageUrl = LessonImageUrl + ) + lesson( + name = "Functor", + tagline = "A type that can be mapped over. A container for a value.", + imageUrl = LessonImageUrl + ) + lesson( + name = "Monad", + tagline = "A type that can be flatMapped over. The heart of FP.", + imageUrl = LessonImageUrl + ) +}) \ No newline at end of file diff --git a/server/src/main/kotlin/ivy/learn/data/cms/course/programming/ObjectOrientedProgramming.kt b/server/src/main/kotlin/ivy/learn/data/cms/course/programming/ObjectOrientedProgramming.kt new file mode 100644 index 00000000..d5de1ea4 --- /dev/null +++ b/server/src/main/kotlin/ivy/learn/data/cms/course/programming/ObjectOrientedProgramming.kt @@ -0,0 +1,56 @@ +package ivy.learn.data.cms.course.programming + +import ivy.learn.data.cms.dsl.CourseDsl +import ivy.learn.data.cms.dsl.CourseImageUrl +import ivy.learn.data.cms.dsl.LessonImageUrl + +object ObjectOrientedProgramming : CourseDsl({ + name = "Object-Oriented Programming (OOP)" + tagline = "Model the world with objects and classes. The foundation of modern software." + imageUrl = CourseImageUrl + lesson( + name = "What is an object?", + tagline = "A self-contained entity with state and behavior.", + imageUrl = LessonImageUrl + ) + lesson( + name = "What is a class?", + tagline = "A blueprint for creating objects. The definition of a type.", + imageUrl = LessonImageUrl + ) + lesson( + name = "Encapsulation", + tagline = "Hiding the internal state of an object and requiring all interaction to be performed through an object's methods.", + imageUrl = LessonImageUrl + ) + lesson( + name = "Inheritance", + tagline = "Creating new classes from existing classes. The 'is-a' relationship.", + imageUrl = LessonImageUrl + ) + lesson( + name = "Polymorphism", + tagline = "The ability of an object to take on many forms. The 'same' method name but different behavior.", + imageUrl = LessonImageUrl + ) + lesson( + name = "Abstraction", + tagline = "Hiding the implementation details of an object and showing only the necessary features.", + imageUrl = LessonImageUrl + ) + lesson( + name = "Interfaces", + tagline = "A contract that defines the behavior of an object. The 'can-do' relationship.", + imageUrl = LessonImageUrl + ) + lesson( + name = "Design Patterns", + tagline = "Solutions to common problems in software design.", + imageUrl = LessonImageUrl + ) + lesson( + name = "SOLID Principles", + tagline = "Guidelines for writing clean, maintainable and scalable code.", + imageUrl = LessonImageUrl + ) +}) \ No newline at end of file diff --git a/server/src/main/kotlin/ivy/learn/data/cms/course/programming/ProgrammingBasics.kt b/server/src/main/kotlin/ivy/learn/data/cms/course/programming/ProgrammingBasics.kt new file mode 100644 index 00000000..cc8c7ee7 --- /dev/null +++ b/server/src/main/kotlin/ivy/learn/data/cms/course/programming/ProgrammingBasics.kt @@ -0,0 +1,46 @@ +package ivy.learn.data.cms.course.programming + +import ivy.learn.data.cms.dsl.CourseDsl +import ivy.learn.data.cms.dsl.LessonImageUrl + +object ProgrammingBasics : CourseDsl({ + name = "Programming Basics" + tagline = "Learn the basics of programming from a different perspective." + imageUrl = + "https://i.ibb.co/nMLdcD5/DALL-E-2024-05-04-20-50-03-A-wide-banner-image-for-a-course-titled-Programming-Basics-with-the-tagli.webp" + lesson( + name = "What is programming?", + tagline = "An introduction to programming. And why we need it?", + imageUrl = LessonImageUrl + ) + lesson( + name = "Computations", + tagline = "The purpose of computers is to compute. What does that mean?", + imageUrl = LessonImageUrl + ) + lesson( + name = "Variables", + tagline = "Storing computations for later use and more.", + imageUrl = LessonImageUrl + ) + lesson( + name = "Branching", + tagline = "This or that? If, when, else, and other choices.", + imageUrl = LessonImageUrl + ) + lesson( + name = "Loops", + tagline = "Doing things over and over again. And again. And again.", + imageUrl = LessonImageUrl + ) + lesson( + name = "Functions", + tagline = "f: A -> B. Extracting computations into reusable units.", + imageUrl = LessonImageUrl + ) + lesson( + name = "Classes", + tagline = "Objects. Functions with shared state. And the heart of OOP.", + imageUrl = LessonImageUrl + ) +}) \ No newline at end of file diff --git a/server/src/main/kotlin/ivy/learn/data/cms/course/programming/ProgrammingFundamentals.kt b/server/src/main/kotlin/ivy/learn/data/cms/course/programming/ProgrammingFundamentals.kt new file mode 100644 index 00000000..28e994de --- /dev/null +++ b/server/src/main/kotlin/ivy/learn/data/cms/course/programming/ProgrammingFundamentals.kt @@ -0,0 +1,26 @@ +package ivy.learn.data.cms.course.programming + +import ivy.learn.data.cms.dsl.CourseDsl +import ivy.learn.data.cms.dsl.CourseImageUrl +import ivy.learn.data.cms.dsl.LessonImageUrl + +object ProgrammingFundamentals : CourseDsl({ + name = "Programming Fundamentals" + tagline = "Explore the core ideas powering today's software." + imageUrl = CourseImageUrl + lesson( + name = "Type Systems", + tagline = "The foundation of modern programming languages.", + imageUrl = LessonImageUrl + ) + lesson( + name = "Algebraic Data Types (ADTs)", + tagline = "SUMs, PRODUCTs and the core of data modeling.", + imageUrl = LessonImageUrl + ) + lesson( + name = "Pattern Matching", + tagline = "The power of ADTs in action.", + imageUrl = LessonImageUrl + ) +}) \ No newline at end of file diff --git a/server/src/main/kotlin/ivy/learn/data/cms/dsl/CmsUtil.kt b/server/src/main/kotlin/ivy/learn/data/cms/dsl/CmsUtil.kt index 78168df7..dea4769b 100644 --- a/server/src/main/kotlin/ivy/learn/data/cms/dsl/CmsUtil.kt +++ b/server/src/main/kotlin/ivy/learn/data/cms/dsl/CmsUtil.kt @@ -3,6 +3,11 @@ package ivy.learn.data.cms.dsl import ivy.model.LessonContent import ivy.model.LessonItemId +val CourseImageUrl = + "https://i.ibb.co/nMLdcD5/DALL-E-2024-05-04-20-50-03-A-wide-banner-image-for-a-course-titled-Programming-Basics-with-the-tagli.webp" +val LessonImageUrl = "https://i.ibb.co/m9kB3cJ/Screenshot-2024-05-04-at-21-22-18.png" + + val EmptyContent = LessonContent( rootItem = LessonItemId(""), items = emptyMap() diff --git a/server/src/test/kotlin/ivy/learn/api/CoursesApiTest.kt b/server/src/test/kotlin/ivy/learn/api/CoursesApiTest.kt index 5cc596eb..38641799 100644 --- a/server/src/test/kotlin/ivy/learn/api/CoursesApiTest.kt +++ b/server/src/test/kotlin/ivy/learn/api/CoursesApiTest.kt @@ -5,7 +5,7 @@ import io.kotest.matchers.shouldBe import ivy.data.source.CoursesDataSource import ivy.data.source.model.CourseResponse import ivy.di.Di -import ivy.learn.data.cms.course.GeneralProgramming +import ivy.learn.data.cms.course.programming.ProgrammingBasics import ivy.learn.testsupport.ApiTest import org.junit.Test @@ -16,12 +16,12 @@ class CoursesApiTest : ApiTest() { val datasource: CoursesDataSource = Di.get() // When - val result = datasource.fetchCourseById(GeneralProgramming.course.id) + val result = datasource.fetchCourseById(ProgrammingBasics.course.id) // Then result.shouldBeRight() shouldBe CourseResponse( - course = GeneralProgramming.course, - lessons = GeneralProgramming.lessons, + course = ProgrammingBasics.course, + lessons = ProgrammingBasics.lessons, ) } } \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/ivy/model/dsl/LearnCmsDsl.kt b/shared/src/commonMain/kotlin/ivy/model/dsl/LearnCmsDsl.kt index 9a49e2cf..8380ce6a 100644 --- a/shared/src/commonMain/kotlin/ivy/model/dsl/LearnCmsDsl.kt +++ b/shared/src/commonMain/kotlin/ivy/model/dsl/LearnCmsDsl.kt @@ -1,28 +1,18 @@ package ivy.model.dsl -import ivy.model.* +import ivy.model.LessonContent +import ivy.model.LessonItemId +import ivy.model.TextContentStyle @LearnCmsDsl -fun lesson( - id: LessonId, - name: String, - tagline: String, - imageUrl: String, - builder: LessonScope.() -> Unit -): Lesson { - val scope = LessonScopeImpl() - scope.builder() - val content = scope.build() - return Lesson( - id = id, - name = name, - tagline = tagline, - image = ImageUrl(imageUrl), - content = content, - ) +fun lessonContent( + builder: LessonContentScope.() -> Unit +): LessonContent { + val scope = LessonContentScopeImpl().apply(builder) + return scope.build() } -interface LessonScope { +interface LessonContentScope { @LearnCmsDsl fun textItem(id: String, builder: TextScope.() -> Unit) diff --git a/shared/src/commonMain/kotlin/ivy/model/dsl/LearnLessonDsl.kt b/shared/src/commonMain/kotlin/ivy/model/dsl/LearnLessonDsl.kt index ca380650..9a32cf4f 100644 --- a/shared/src/commonMain/kotlin/ivy/model/dsl/LearnLessonDsl.kt +++ b/shared/src/commonMain/kotlin/ivy/model/dsl/LearnLessonDsl.kt @@ -2,7 +2,7 @@ package ivy.model.dsl import ivy.model.* -class LessonScopeImpl : LessonScope { +class LessonContentScopeImpl : LessonContentScope { private var rootItem: LessonItemId? = null private var currentItem: LessonItemId? = null private val items = mutableMapOf() diff --git a/shared/src/commonMain/kotlin/ivy/model/dsl/lesson/ProgrammingFundamentals101.kt b/shared/src/commonMain/kotlin/ivy/model/dsl/lesson/ProgrammingFundamentals101.kt deleted file mode 100644 index f5da18ac..00000000 --- a/shared/src/commonMain/kotlin/ivy/model/dsl/lesson/ProgrammingFundamentals101.kt +++ /dev/null @@ -1,29 +0,0 @@ -package ivy.model.dsl.lesson - -import ivy.model.LessonId -import ivy.model.LessonItemId -import ivy.model.TextContentStyle -import ivy.model.dsl.lesson - -fun programmingFundamentals101() = lesson( - id = LessonId("programming-fundamentals-101"), - name = "Programming Fundamentals 101", - tagline = "Learn the basics of programming", - imageUrl = "TBD" -) { - mystery("question-1-answer") { - text("Show explanation") - hiddenItemId(LessonItemId("question-1-explanation")) - } - textItem("question-1-explanation") { - text("1 + 1 = 2") - style(TextContentStyle.Body) - } - question("question-1") { - questionText("What is 1 + 1?") - answer("1", "1 + 1 = 2", false) - answer("2", "1 + 1 = 2", true) - answer("3", "1 + 1 = 2", false) - answer("4", "1 + 1 = 2", false) - } -} \ No newline at end of file