commit dc948cbb854f4728b32940afcaeb245412c6ba43
parent 72b52a63f2bc456d639f2dcbab8dac3f17bc791a
Author: Andrew Laack <andrew@laack.co>
Date: Thu, 27 Aug 2026 18:55:08 -0500
This should be refactored soon, but added shared sidebar + preformatted sections and some other stuff
Diffstat:
7 files changed, 73 insertions(+), 112 deletions(-)
diff --git a/courses/ocaml/0_ocaml.sl b/courses/ocaml/0_ocaml.sl
@@ -8,74 +8,16 @@ OCaml is the acronym for Objective Categorical Abstract Machine Language.
In OCaml we use the 'let' keyword to bind a expressions to names (variables). Shown below is an example of this:
-```ocaml
-let x = 10
```
-
-## Syntax
-
-In OCaml we use the 'let' keyword to bind a expressions to names (variables). Shown below is an example of this:
-
-```ocaml
-let x = 10
-```
-
-## Syntax
-
-In OCaml we use the 'let' keyword to bind a expressions to names (variables). Shown below is an example of this:
-
-```ocaml
-let x = 10
-```
-
-## Syntax
-
-In OCaml we use the 'let' keyword to bind a expressions to names (variables). Shown below is an example of this:
-
-```ocaml
-let x = 10
-```
-
-## Syntax
-
-In OCaml we use the 'let' keyword to bind a expressions to names (variables). Shown below is an example of this:
-
-```ocaml
-let x = 10
-```
-
-## Syntax
-
-In OCaml we use the 'let' keyword to bind a expressions to names (variables). Shown below is an example of this:
-
-```ocaml
-let x = 10
-```
-
-## Syntax
-
-In OCaml we use the 'let' keyword to bind a expressions to names (variables). Shown below is an example of this:
-
-```ocaml
-let x = 10
-```
-
-## Syntax
-
-In OCaml we use the 'let' keyword to bind a expressions to names (variables). Shown below is an example of this:
-
-```ocaml
-let x = 10
-```
-
-## Syntax
-
-In OCaml we use the 'let' keyword to bind a expressions to names (variables). Shown below is an example of this:
-
-```ocaml
-let x = 10
+let factorial x =
+ let rec go acc current =
+ if current = 0
+ then acc
+ else
+ go (acc * current) (current - 1)
+ in go 1 x;;
+print_endline (string_of_int(factorial 6));;
```
-
=>i em.png
=>v out.webm
diff --git a/learning/bin/main.ml b/learning/bin/main.ml
@@ -15,24 +15,37 @@ type page_line = {
content: string;
is_embedded_video: bool;
is_embedded_image: bool;
+ is_preformatted: bool;
}
-let parse_simple_line line =
- let hash_count = countPrefix '#' line in
- let embedded_video = if String.length(line) > 3 && line.[0] = '=' && line.[1] = '>' && line.[2] = 'v' then true else false in
- let embedded_image = if String.length(line) > 3 && line.[0] = '=' && line.[1] = '>' && line.[2] = 'i' then true else false in
- {header_level = hash_count; content = (if embedded_video || embedded_image then (String.sub line 4 (String.length(line) - 4)) else line); is_embedded_image = embedded_image; is_embedded_video = embedded_video}
+let parse_simple_line line preformatted =
+ let hash_count = if not preformatted then countPrefix '#' line else 0 in
+ let embedded_video = if not preformatted && String.length(line) > 3 && line.[0] = '=' && line.[1] = '>' && line.[2] = 'v' then true else false in
+ let embedded_image = if not preformatted && String.length(line) > 3 && line.[0] = '=' && line.[1] = '>' && line.[2] = 'i' then true else false in
+ {header_level = hash_count; content = (if embedded_video || embedded_image then (String.sub line 4 (String.length(line) - 4)) else line); is_embedded_image = embedded_image; is_embedded_video = embedded_video; is_preformatted = preformatted}
+
+let is_format_line cl =
+ String.length cl = 3 && cl.[0] = '`' && cl.[1] = '`' && cl.[2] = '`'
let read_simple_learning_file fileName =
let ic = open_in fileName in
- let rec readAll () =
+ let rec readAll preformatted acc =
try
- let current_line = parse_simple_line (input_line ic) in
- current_line :: readAll ();
+ let cl = input_line ic in
+ let current_format = if is_format_line cl then not preformatted else preformatted in
+ if not current_format && not preformatted then
+ let current_line = parse_simple_line cl current_format in
+ if String.length acc != 0
+ then
+ parse_simple_line acc true :: current_line :: readAll current_format ""
+ else
+ current_line :: readAll current_format ""
+ else
+ readAll current_format (if not (is_format_line cl) then (if String.length acc != 0 then acc ^ "\n" ^ cl else cl) else acc)
with End_of_file ->
close_in_noerr ic;
- []
- in readAll ()
+ if String.length acc != 0 then parse_simple_line acc true :: [] else []
+ in readAll false ""
let readFile fileName =
let ic = open_in fileName in
@@ -52,7 +65,7 @@ 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); ("is_embedded_video", Jg_types.Tbool line.is_embedded_video); ("is_embedded_image", Jg_types.Tbool line.is_embedded_image)]
+ Jg_types.Tobj [("header_level", Jg_types.Tint line.header_level); ("content", Jg_types.Tstr line.content); ("is_embedded_video", Jg_types.Tbool line.is_embedded_video); ("is_embedded_image", Jg_types.Tbool line.is_embedded_image); ("is_preformatted", Jg_types.Tbool line.is_preformatted)]
let get_courses =
let arr = Sys.readdir course_dir in
@@ -99,14 +112,19 @@ 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 render_sidebar s =
+ (Jg_template.from_file "./templates/sidebar.jingoo" ~models:[("courses", get_courses)]) ^ s
+
+
let () =
Dream.run
@@ Dream.logger
@@ Dream.router [
- 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 "/course/:course_name/" (fun request -> Dream.html (render_sidebar @@ render_course_home (Dream.param request "course_name")));
+ Dream.get "/course/:course_name/page/:page_name" (fun request -> Dream.html @@ render_sidebar @@ 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);
+ Dream.get "/" (fun _ -> Dream.html (render_sidebar @@ render_course_list));
Dream.get "/course/:course_name/page/assets/**" (fun request -> Dream.static
(course_dir ^ (Dream.param request "course_name") ^ "/assets") request);
]
diff --git a/learning/static/styles.css b/learning/static/styles.css
@@ -25,6 +25,23 @@ h6 {
color: #700000 ;
}
+pre-formatted {
+ background: #f4f4f4;
+ border: 1px solid #ddd;
+ border-left: 3px solid #f36d33;
+ color: #666;
+ page-break-inside: avoid;
+ font-family: monospace;
+ font-size: 15px;
+ line-height: 1.6;
+ margin-bottom: 1.6em;
+ max-width: 100%;
+ overflow: auto;
+ padding: 1em 1.5em;
+ display: block;
+ word-wrap: break-word;
+}
+
content-block {
display: block;
color: #222222;
diff --git a/learning/templates/course_home.jingoo b/learning/templates/course_home.jingoo
@@ -1,12 +1,5 @@
-<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">
+ <h1> Pages </h1>
<ul>
{% for page in pages %}
<li><a href="page/{{ page.name }}">{{ page.name }}</a></li>
diff --git a/learning/templates/course_list.jingoo b/learning/templates/course_list.jingoo
@@ -1,12 +1,5 @@
-<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">
+ <h1> Courses </h1>
<ul>
{% for course in courses %}
<li><a href="/course/{{ course.name }}/">{{ course.name }}</a></li>
diff --git a/learning/templates/course_page.jingoo b/learning/templates/course_page.jingoo
@@ -1,24 +1,15 @@
-<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 %}
+ {% if line.is_preformatted %}
+ <pre><pre-formatted>{{line.content}}</pre-formatted></pre>
+ {% else 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 %}
- {% if line.is_embedded_image %}
+ {% else if line.is_embedded_image %}
<img src=assets/{{line.content}}> </img>
- {% endif %}
- {% if line.is_embedded_video %}
+ {% else if line.is_embedded_video %}
<video> <source src="assets/{{line.content}}"> Your browser does not support the video tag. </video>
+ {% else if line.header_level == 0 %}
+ <content-block>{{line.content}}</content-block>
{% endif %}
{% endfor %}
</div>
diff --git a/learning/templates/sidebar.jingoo b/learning/templates/sidebar.jingoo
@@ -0,0 +1,7 @@
+<link rel="stylesheet" href="/static/styles.css" type="text/css">
+<div class="sidenav">
+ <a href="/">Home</a>
+ {% for course in courses %}
+ <a href="/course/{{ course.name }}/">{{ course.name }}</a>
+ {% endfor %}
+</div>