simple-learning

Simple learning web program
git clone git://git.laack.co/simple-learning.git
Log | Files | Refs | README | LICENSE

commit 0bcb945484402054d96b88d414fdf8321ab1e8ce
parent dcf547b4e169d852acba76b3ab915dec16a05d04
Author: Andrew Laack <andrew@laack.co>
Date:   Thu, 27 Aug 2026 15:14:32 -0500

Refactoring and stuff

Diffstat:
Rcourses/haskell/0_haskell.rl -> courses/haskell/0_haskell.sl | 0
Rcourses/haskell/1_haskell.rl -> courses/haskell/1_haskell.sl | 0
Rcourses/ocaml/0_ocaml.rl -> courses/ocaml/0_ocaml.sl | 0
Rcourses/ocaml/1_ocaml.rl -> courses/ocaml/1_ocaml.sl | 0
Mlearning/bin/main.ml | 45+++++++++++++++++++++++++++++++++++++++++----
Mlearning/static/styles.css | 2+-
Alearning/templates/course_page.jingoo | 18++++++++++++++++++
Doutputs/out.html | 36------------------------------------
Doutputs/styles.css | 39---------------------------------------
9 files changed, 60 insertions(+), 80 deletions(-)

diff --git a/courses/haskell/0_haskell.rl b/courses/haskell/0_haskell.sl diff --git a/courses/haskell/1_haskell.rl b/courses/haskell/1_haskell.sl diff --git a/courses/ocaml/0_ocaml.rl b/courses/ocaml/0_ocaml.sl diff --git a/courses/ocaml/1_ocaml.rl b/courses/ocaml/1_ocaml.sl diff --git a/learning/bin/main.ml b/learning/bin/main.ml @@ -2,7 +2,36 @@ open Jingoo let course_dir = "../courses/" -let readFile fileName = +let countPrefix char data = + let rec go idx = + if String.length data > idx && data.[idx] = char + then + go (idx + 1) + else idx + in go 0 + + +type page_line = { + header_level: int; + content: string; +} + +let parse_simple_line line = + let hash_count = countPrefix '#' line in + {header_level = hash_count; content = line} + +let read_simple_learning_file fileName = + let ic = open_in fileName in + let rec readAll () = + try + let current_line = parse_simple_line (input_line ic) in + current_line :: readAll (); + with End_of_file -> + close_in_noerr ic; + [] + in readAll () + +let readFile fileName = let ic = open_in fileName in let rec readAll acc = try @@ -19,6 +48,8 @@ let remove_file_extension file_name = let to_tval value = Jg_types.Tobj [("name", Jg_types.Tstr value);] +let page_line_to_tobj line = + Jg_types.Tobj [("header_level", Jg_types.Tint line.header_level); ("content", Jg_types.Tstr line.content)] let get_courses = let arr = Sys.readdir course_dir in @@ -47,19 +78,25 @@ let arr_to_string arr = else go (acc ^ arr.(idx)) (idx + 1) in go "" 0 - - let get_course_home course_name = Array.map to_tval (get_pages_in_order course_name) let render_course_home course_name = (Jg_template.from_file "./templates/course_home.jingoo" ~models:[("pages", (Jg_types.Tlist (Array.to_list (get_course_home course_name))))]) +let get_path_to_page course page = + course_dir ^ course ^ "/" ^ page + +let render_page course page = + let page_lines = read_simple_learning_file @@ get_path_to_page course page in + (Jg_template.from_file "./templates/course_page.jingoo" ~models:(["lines", Jg_types.Tlist (List.map page_line_to_tobj page_lines)])) + let () = Dream.run @@ Dream.logger @@ Dream.router [ - Dream.get "/course/:id/" (fun request -> Dream.html (render_course_home (Dream.param request "id"))); + Dream.get "/course/:course_name/" (fun request -> Dream.html (render_course_home (Dream.param request "course_name"))); + Dream.get "/course/:course_name/page/:page_name" (fun request -> Dream.html @@ render_page (Dream.param request "course_name") (Dream.param request "page_name")); Dream.get "/static/**" (Dream.static "./static"); Dream.get "/" (fun _ -> Dream.html render_course_list) ] diff --git a/learning/static/styles.css b/learning/static/styles.css @@ -27,7 +27,7 @@ h6 { content-block { display: block; - color: #000000; + color: #222222; } .sidenav { diff --git a/learning/templates/course_page.jingoo b/learning/templates/course_page.jingoo @@ -0,0 +1,18 @@ +<link rel="stylesheet" href="/static/styles.css" type="text/css"> +<div class="sidenav"> + <a href="/">Home</a> + <a href="">Services</a> + <a href="">Clients</a> + <a href="">Contact</a> +</div> + +<div class="main"> + {% for line in lines %} + {% if line.header_level >= 1 %} + <h{{line.header_level}}>{{line.content}}</h{{line.header_level}}> + {% endif %} + {% if line.header_level == 0 %} + <content-block>{{line.content}}</content-block> + {% endif %} + {% endfor %} +</div> diff --git a/outputs/out.html b/outputs/out.html @@ -1,36 +0,0 @@ -<link rel="stylesheet" href="styles.css" type="text/css"> -<div class="sidenav"> - <a href="#">About</a> - <a href="#">Services</a> - <a href="#">Clients</a> - <a href="#">Contact</a> -</div> - -<div class="main"> -<h1># OCaml</h1> -<content-block></content-block> -<h2>## History</h2> -<content-block></content-block> -<content-block>OCaml is the acronym for Objective Categorical Abstract Machine Language. </content-block> -<content-block></content-block> -<h2>## Syntax</h2> -<content-block></content-block> -<content-block>In OCaml we use the 'let' keyword to bind a expressions to names (variables). Shown below is an example of this:</content-block> -<content-block></content-block> -<content-block>```ocaml</content-block> -<content-block>let x = 10</content-block> -<content-block>```</content-block> - -<content-block></content-block> -<content-block>```ocaml</content-block> -<content-block>let x = 10</content-block> -<content-block>```</content-block> -<content-block></content-block> -<content-block>```ocaml</content-block> -<content-block>let x = 10</content-block> -<content-block>```</content-block> -<content-block></content-block> -<content-block>```ocaml</content-block> -<content-block>let x = 10</content-block> -<content-block>```</content-block> -</div> diff --git a/outputs/styles.css b/outputs/styles.css @@ -1,39 +0,0 @@ -body { - font-family: Arial, sans-serif; - background-color: #f3f6f9; - margin: 0; -} -h1 { - color: #000000; -} - -content-block { - background-color: #f6f9fB; - display: block; -} - -.sidenav { - height: 100%; /* Full-height: remove this if you want "auto" height */ - width: 160px; /* Set the width of the sidebar */ - position: fixed; /* Fixed Sidebar (stay in place on scroll) */ - z-index: 1; /* Stay on top */ - top: 0; /* Stay at the top */ - left: 0; - background-color: #111; /* Black */ - overflow-x: hidden; /* Disable horizontal scroll */ - padding-top: 20px; -} - -/* The navigation menu links */ -.sidenav a { - padding: 6px 8px 6px 16px; - text-decoration: none; - font-size: 25px; - color: #A18181; - display: block; -} - -.main { - margin-left: 160px; /* Same as the width of the sidebar */ - padding: 0px 10px; -}