package website import ( "context" "errors" "fmt" "html/template" "net/http" "net/url" "regexp" "strconv" "strings" "time" "git.handmade.network/hmn/hmn/src/db" "git.handmade.network/hmn/hmn/src/hmnurl" "git.handmade.network/hmn/hmn/src/models" "git.handmade.network/hmn/hmn/src/parsing" "git.handmade.network/hmn/hmn/src/templates" "git.handmade.network/hmn/hmn/src/utils" ) func EducationIndex(c *RequestContext) ResponseData { type indexData struct { templates.BaseData Courses []templates.EduCourse NewArticleUrl string RerenderUrl string } // TODO: Someday this can be dynamic again? Maybe? Or not? Who knows?? // articles, err := fetchEduArticles(c, c.Conn, models.EduArticleTypeArticle, c.CurrentUser) // if err != nil { // panic(err) // } // var tmplArticles []templates.EduArticle // for _, article := range articles { // tmplArticles = append(tmplArticles, templates.EducationArticleToTemplate(&article)) // } article := func(slug string) templates.EduArticle { if article, err := fetchEduArticle(c, c.Conn, slug, models.EduArticleTypeArticle, c.CurrentUser); err == nil { return templates.EducationArticleToTemplate(article) } else if errors.Is(err, db.NotFound) { return templates.EduArticle{ Title: "", } } else { panic(err) } } tmpl := indexData{ BaseData: getBaseData(c, "Handmade Education", nil), Courses: []templates.EduCourse{ { Name: "Compilers", Slug: "compilers", Articles: []templates.EduArticle{ article("compilers"), { Title: "Baby's first language theory", Description: "State machines, abstract datatypes, type theory...", }, }, }, { Name: "Networking", Slug: "networking", Articles: []templates.EduArticle{ article("http"), { Title: "Internet infrastructure", Description: "How does the internet actually work? How does your ISP know where to send your data? What happens to the internet if physical communication breaks down?", }, }, }, { Name: "Time", Slug: "time", Articles: []templates.EduArticle{ article("time"), article("ntp"), }, }, }, NewArticleUrl: hmnurl.BuildEducationArticleNew(), RerenderUrl: hmnurl.BuildEducationRerender(), } var res ResponseData res.MustWriteTemplate("education_index.html", tmpl, c.Perf) return res } func EducationGlossary(c *RequestContext) ResponseData { type glossaryData struct { templates.BaseData } tmpl := glossaryData{ BaseData: getBaseData(c, "Handmade Education", nil), } var res ResponseData res.MustWriteTemplate("education_glossary.html", tmpl, c.Perf) return res } var reImg = regexp.MustCompile(`(.*?)`) var reNotSimple = regexp.MustCompile(`[^a-zA-Z0-9-_]+`) var reEduEditorsNote = regexp.MustCompile(`(?s).*?`) var reEduEditorsNoteTmp = regexp.MustCompile(`<<>>`) type TOCEntry struct { Text string ID string Level int } func generateTOC(html string, canSeeNotes bool) (string, []TOCEntry) { var notes []string replacinated := reEduEditorsNote.ReplaceAllStringFunc(html, func(s string) string { i := len(notes) notes = append(notes, s) if canSeeNotes { return fmt.Sprintf("<<>>", i) } else { return "" } }) var entries []TOCEntry replacinated = reHeading.ReplaceAllStringFunc(replacinated, func(s string) string { m := reHeading.FindStringSubmatch(s) level := m[1] content := m[2] id := strings.ToLower(reNotSimple.ReplaceAllLiteralString(content, "-")) entries = append(entries, TOCEntry{ Text: content, ID: id, Level: utils.Must1(strconv.Atoi(level)), }) return fmt.Sprintf(`%s`, level, id, content, level) }) replacinated = reEduEditorsNoteTmp.ReplaceAllStringFunc(replacinated, func(s string) string { m := reEduEditorsNoteTmp.FindStringSubmatch(s) i, _ := strconv.Atoi(m[1]) return notes[i] }) return replacinated, entries }