bootstrap migrate

This commit is contained in:
2024-03-04 00:03:08 +03:00
parent 251ecd94d4
commit 97986063df
9 changed files with 1012 additions and 83 deletions

View File

@ -1 +1 @@
898c2e71a27ba82ceae47d2745b8f599 ba89728e33b4eb652254d64099b17c4

View File

@ -54,8 +54,9 @@ tasks:
cmds: cmds:
- task: build_dev_cli - task: build_dev_cli
- task: build_background - task: build_background
- task: build_web
run: run:
deps: [build] deps: [build]
cmds: cmds:
- $GOBIN/sravnicli - $GOBIN/kuriousweb

View File

@ -41,7 +41,7 @@
<div class="container"> <div class="container">
<header class="row header"> <section class="row header">
<nav class="mt-4" style="--bs-breadcrumb-divider: '/';" aria-label="breadcrumb"> <nav class="mt-4" style="--bs-breadcrumb-divider: '/';" aria-label="breadcrumb">
<ol class="breadcrumb"> <ol class="breadcrumb">
<li class="breadcrumb-item"><a href="#">Main</a></li> <li class="breadcrumb-item"><a href="#">Main</a></li>
@ -49,7 +49,7 @@
<li class="breadcrumb-item active" aria-current="page">Japanese</li> <li class="breadcrumb-item active" aria-current="page">Japanese</li>
</ol> </ol>
</nav> </nav>
</header> </section>
<section class="row filters"> <section class="row filters">

View File

@ -16,62 +16,78 @@ templ head(title string) {
integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL" integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL"
crossorigin="anonymous"> crossorigin="anonymous">
</script> </script>
<link rel="stylesheet" href="/assets/style.css"/>
</head> </head>
} }
templ navbar(active int) { templ headerNavbar(page PageKind) {
<nav class="navbar navbar-expand-lg bg-body-tertiary w-auto"> <header>
<div class="container-fluid"> <nav class="navbar navbar-expand-lg bg-body-tertiary w-auto">
<a class="navbar-brand" href="/htmlexamples/index.html">Kurious</a> <div class="container-fluid">
<a class="navbar-brand" href="/htmlexamples/index.html">Kurious</a>
<button <button
class="navbar-toggler" type="button" class="navbar-toggler" type="button"
data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent" aria-expanded="false" aria-controls="navbarSupportedContent" aria-expanded="false"
aria-label="Toggle navigation" aria-label="Toggle navigation"
> >
<span class="navbar-toggler-icon"></span> <span class="navbar-toggler-icon"></span>
</button> </button>
<div class="collapse navbar-collapse" id="navbarSupportedContent"> <div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0"> <ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item"> <li class="nav-item">
<a <a
class={"nav-link", templ.KV("active", active == 0)} class={"nav-link", templ.KV("active", page == PageIndex)}
aria-current="page" aria-current="page"
href="/"> href="/">
Home Home
</a> </a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a <a
class={"nav-link", templ.KV("active", active == 1)} class={"nav-link", templ.KV("active", page == PageCourses)}
aria-current="page" aria-current="page"
href="/courses" href="/courses"
> >
Courses Courses
</a> </a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a <a
class={"nav-link", templ.KV("active", active == 2)} class={"nav-link", templ.KV("active", page == PageAbout)}
href="/about" href="/about"
> >
About us About us
</a> </a>
</li> </li>
</ul> </ul>
</div>
</div> </div>
</div> </nav>
</nav> </header>
} }
templ footer() { templ footer() {
<footer> <footer>
<div> <div class="row">
<span>(c) kurious, 2024. All rights reserved.</span> <span>(c) kurious, 2024. All rights reserved.</span>
</div> </div>
</footer> </footer>
} }
templ root(page PageKind, s stats) {
<!DOCTYPE html>
<html lang="ru">
@head(string(page))
<body>
@headerNavbar(page)
<div class="container">
{ children... }
</div>
@breadcrumbsLoad()
</body>
</html>
}

View File

@ -10,7 +10,7 @@ import "context"
import "io" import "io"
import "bytes" import "bytes"
func head() templ.Component { func head(title string) templ.Component {
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
if !templ_7745c5c3_IsBuffer { if !templ_7745c5c3_IsBuffer {
@ -27,8 +27,12 @@ func head() templ.Component {
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
templ_7745c5c3_Var2 := `Test page` var templ_7745c5c3_Var2 string
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var2) templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(title)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/kurious/ports/http/bootstrap/core.templ`, Line: 4, Col: 16}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
@ -36,7 +40,8 @@ func head() templ.Component {
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
templ_7745c5c3_Var3 := `` templ_7745c5c3_Var3 := `
`
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var3) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var3)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
@ -52,7 +57,7 @@ func head() templ.Component {
}) })
} }
func navbar() templ.Component { func headerNavbar(page PageKind) templ.Component {
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
if !templ_7745c5c3_IsBuffer { if !templ_7745c5c3_IsBuffer {
@ -65,7 +70,7 @@ func navbar() templ.Component {
templ_7745c5c3_Var4 = templ.NopComponent templ_7745c5c3_Var4 = templ.NopComponent
} }
ctx = templ.ClearChildren(ctx) ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<nav class=\"navbar navbar-expand-lg bg-body-tertiary w-auto\"><div class=\"container-fluid\"><a class=\"navbar-brand\" href=\"#\">") _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<header><nav class=\"navbar navbar-expand-lg bg-body-tertiary w-auto\"><div class=\"container-fluid\"><a class=\"navbar-brand\" href=\"/htmlexamples/index.html\">")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
@ -74,25 +79,85 @@ func navbar() templ.Component {
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a> <button class=\"navbar-toggler\" type=\"button\" data-bs-toggle=\"collapse\" data-bs-target=\"#navbarSupportedContent\" aria-controls=\"navbarSupportedContent\" aria-expanded=\"false\" aria-label=\"Toggle navigation\"><span class=\"navbar-toggler-icon\"></span></button><div class=\"collapse navbar-collapse\" id=\"navbarSupportedContent\"><ul class=\"navbar-nav me-auto mb-2 mb-lg-0\"><li class=\"nav-item\"><a class=\"nav-link active\" aria-current=\"page\" href=\"#\">") _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a> <button class=\"navbar-toggler\" type=\"button\" data-bs-toggle=\"collapse\" data-bs-target=\"#navbarSupportedContent\" aria-controls=\"navbarSupportedContent\" aria-expanded=\"false\" aria-label=\"Toggle navigation\"><span class=\"navbar-toggler-icon\"></span></button><div class=\"collapse navbar-collapse\" id=\"navbarSupportedContent\"><ul class=\"navbar-nav me-auto mb-2 mb-lg-0\"><li class=\"nav-item\">")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
templ_7745c5c3_Var6 := `На главную` var templ_7745c5c3_Var6 = []any{"nav-link", templ.KV("active", page == PageIndex)}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var6) templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var6...)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></li><li class=\"nav-item\"><a class=\"nav-link\" href=\"#\">") _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<a class=\"")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
templ_7745c5c3_Var7 := `О нас` _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ.CSSClasses(templ_7745c5c3_Var6).String()))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" aria-current=\"page\" href=\"/\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Var7 := `Home`
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var7) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var7)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></li></ul></div></div></nav>") _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></li><li class=\"nav-item\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var8 = []any{"nav-link", templ.KV("active", page == PageCourses)}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var8...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<a class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ.CSSClasses(templ_7745c5c3_Var8).String()))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" aria-current=\"page\" href=\"/courses\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Var9 := `Courses`
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var9)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></li><li class=\"nav-item\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var10 = []any{"nav-link", templ.KV("active", page == PageAbout)}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var10...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<a class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ.CSSClasses(templ_7745c5c3_Var10).String()))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" href=\"/about\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Var11 := `About us`
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var11)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></li></ul></div></div></nav></header>")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
@ -111,17 +176,17 @@ func footer() templ.Component {
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
} }
ctx = templ.InitializeContext(ctx) ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var8 := templ.GetChildren(ctx) templ_7745c5c3_Var12 := templ.GetChildren(ctx)
if templ_7745c5c3_Var8 == nil { if templ_7745c5c3_Var12 == nil {
templ_7745c5c3_Var8 = templ.NopComponent templ_7745c5c3_Var12 = templ.NopComponent
} }
ctx = templ.ClearChildren(ctx) ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<footer><div><span>") _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<footer><div class=\"row\"><span>")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
templ_7745c5c3_Var9 := `(c) kurious, 2024. All rights reserved.` templ_7745c5c3_Var13 := `(c) kurious, 2024. All rights reserved.`
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var9) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var13)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
@ -135,3 +200,59 @@ func footer() templ.Component {
return templ_7745c5c3_Err return templ_7745c5c3_Err
}) })
} }
func root(page PageKind, s stats) templ.Component {
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
if !templ_7745c5c3_IsBuffer {
templ_7745c5c3_Buffer = templ.GetBuffer()
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var14 := templ.GetChildren(ctx)
if templ_7745c5c3_Var14 == nil {
templ_7745c5c3_Var14 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<!doctype html><html lang=\"ru\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = head(string(page)).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<body>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = headerNavbar(page).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"container\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ_7745c5c3_Var14.Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = breadcrumbsLoad().Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</body></html>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if !templ_7745c5c3_IsBuffer {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
}
return templ_7745c5c3_Err
})
}

View File

@ -1,5 +1,8 @@
package bootstrap package bootstrap
import "path"
import "strconv"
script breadcrumbsLoad() { script breadcrumbsLoad() {
const formFilterOnSubmit = event => { const formFilterOnSubmit = event => {
event.preventDefault(); event.preventDefault();
@ -24,9 +27,11 @@ script breadcrumbsLoad() {
templ breadcrumbsItem(text, link string, isActive bool) { templ breadcrumbsItem(text, link string, isActive bool) {
<li class={"breadcrumb-item", templ.KV("active", isActive)}> <li class={"breadcrumb-item", templ.KV("active", isActive)}>
if link != "" { if link != "" {
<a href={ templ.SafeURL(link) } itemprop="url"> <a
<span itemprop="title">{ text }</span> href={templ.URL(link)}
</a> itemprop="url"
aria-label="breadcrumb"
>{ text }</a>
} else { } else {
<span itemprop="url" itemprop="title">{ text }</span> <span itemprop="url" itemprop="title">{ text }</span>
} }
@ -36,14 +41,143 @@ templ breadcrumbsItem(text, link string, isActive bool) {
templ breadcrumNode(params BreadcrumbsParams) { templ breadcrumNode(params BreadcrumbsParams) {
// TODO: add divider to nav style // TODO: add divider to nav style
<nav <nav
class={"mt-4", breadcrumbSymbol()}
aria-label="breadcrumbs" aria-label="breadcrumbs"
itemprop="breadcrumb" itemprop="breadcrumb"
itemtype="https://schema.org/BreadcrumbList" itemtype="https://schema.org/BreadcrumbList"
itemscope itemscope
> >
<ol class="breadcrumb"> <ol class="breadcrumb">
@breadcrumbsItem("Курсы", "/courses", params.ActiveCourseThematic.Empty()) @breadcrumbsItem("Курсы", "/courses", params.ActiveLearningType.Empty())
if !params.ActiveLearningType.Empty() {
@breadcrumbsItem(
params.ActiveLearningType.Name,
path.Join("/", "courses", params.ActiveLearningType.ID),
params.ActiveCourseThematic.Empty(),
)
}
if !params.ActiveCourseThematic.Empty() {
@breadcrumbsItem(
params.ActiveCourseThematic.Name,
path.Join("/", "courses", params.ActiveLearningType.ID, params.ActiveCourseThematic.ID),
true,
)
}
</ol> </ol>
</nav> </nav>
} }
css breadcrumbSymbol() {
--bs-breadcrumb-divider: "/";
}
templ listCoursesSectionHeader(params BreadcrumbsParams) {
<section class="row bc-header">
@breadcrumNode(params)
</section>
}
templ listCoursesSectionFilters(params FilterFormParams) {
<section class="row filters">
<div class="col-8">
<form id="filter-form" class="input-group">
<span class="input-group-text">Filter courses</span>
<select
id="learning-type-filter"
class={"form-select"}
>
<option selected?={params.ActiveLearningType.ID==""}>All</option>
for _, learningType := range params.AvailableLearningTypes {
<option
selected?={params.ActiveLearningType.ID==learningType.ID}
value={learningType.ID}
>{learningType.Name}</option>
}
</select>
<select
id="course-thematic-filter"
class={"form-select", templ.KV("d-none", len(params.AvailableCourseThematics) == 0)}
>
<option selected?={params.ActiveLearningType.ID==""}>All</option>
for _, courseThematic := range params.AvailableCourseThematics {
<option
selected?={params.ActiveCourseThematic.ID==courseThematic.ID}
value={courseThematic.ID}
>{courseThematic.Name}</option>
}
</select>
<button class="btn btn-outline-secondary" type="button">Go</button>
</form>
</div>
</section>
}
templ listCoursesLearning(containers []CategoryContainer) {
for _, container := range containers {
<section class="row first-class-group">
<h1 class="title">{container.Name}</h1>
<p>{container.Description}</p>
<div class="block">Placeholder for filter</div>
for _, subcategory := range container.Subcategories {
@listCoursesThematicRow(subcategory)
}
</section>
}
}
templ listCoursesThematicRow(subcategory SubcategoryContainer) {
<div class="block second-class-group">
<h2 class="title">{subcategory.Name}</h2>
<p>{subcategory.Description}</p>
<div class="row g-4">
for _, info := range subcategory.Courses {
@listCoursesCard(info)
}
</div>
</div>
}
css myImg() {
min-height: 19rem;
min-width: 19rem;
}
css cardTextSize() {
min-height: 16rem;
}
templ listCoursesCard(info CourseInfo) {
<div class="col-12 col-md-6 col-lg-3">
<div class="card">
<img src={ GetOrFallback(info.ImageLink, "https://placehold.co/128x128")} alt="Course picture" class={"card-img-top", myImg()}/>
<div class={"card-body", cardTextSize()}>
<h5 class="card-title">{info.Name}</h5>
<div class="input-group d-flex">
<a
href={ templ.URL(info.OriginLink) }
class="btn text btn-outline-primary flex-grow-1"
>Go!</a>
<span class="input-group-text justify-content-end flex-fill">
{strconv.Itoa(info.FullPrice)} rub.
</span>
</div>
</div>
</div>
</div>
}
templ ListCourses(pageType PageKind, s stats, params ListCoursesParams) {
@root(pageType, s) {
@listCoursesSectionHeader(params.FilterForm.BreadcrumbsParams)
@listCoursesSectionFilters(params.FilterForm)
@listCoursesLearning(params.Categories)
}
}

View File

@ -9,6 +9,10 @@ import "github.com/a-h/templ"
import "context" import "context"
import "io" import "io"
import "bytes" import "bytes"
import "strings"
import "path"
import "strconv"
func breadcrumbsLoad() templ.ComponentScript { func breadcrumbsLoad() templ.ComponentScript {
return templ.ComponentScript{ return templ.ComponentScript{
@ -71,25 +75,25 @@ func breadcrumbsItem(text, link string, isActive bool) templ.Component {
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
var templ_7745c5c3_Var3 templ.SafeURL = templ.SafeURL(link) var templ_7745c5c3_Var3 templ.SafeURL = templ.URL(link)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var3))) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var3)))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" itemprop=\"url\"><span itemprop=\"title\">") _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" itemprop=\"url\" aria-label=\"breadcrumb\">")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
var templ_7745c5c3_Var4 string var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(text) templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(text)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/kurious/ports/http/bootstrap/list.templ`, Line: 27, Col: 33} return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/kurious/ports/http/bootstrap/list.templ`, Line: 33, Col: 10}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</span></a>") _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a>")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
@ -101,7 +105,7 @@ func breadcrumbsItem(text, link string, isActive bool) templ.Component {
var templ_7745c5c3_Var5 string var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(text) templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(text)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/kurious/ports/http/bootstrap/list.templ`, Line: 30, Col: 47} return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/kurious/ports/http/bootstrap/list.templ`, Line: 35, Col: 47}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
@ -136,14 +140,47 @@ func breadcrumNode(params BreadcrumbsParams) templ.Component {
templ_7745c5c3_Var6 = templ.NopComponent templ_7745c5c3_Var6 = templ.NopComponent
} }
ctx = templ.ClearChildren(ctx) ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<nav aria-label=\"breadcrumbs\" itemprop=\"breadcrumb\" itemtype=\"https://schema.org/BreadcrumbList\" itemscope><ol class=\"breadcrumb\">") var templ_7745c5c3_Var7 = []any{"mt-4", breadcrumbSymbol()}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var7...)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
templ_7745c5c3_Err = breadcrumbsItem("Курсы", "/courses", params.ActiveCourseThematic.Empty()).Render(ctx, templ_7745c5c3_Buffer) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<nav class=\"")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ.CSSClasses(templ_7745c5c3_Var7).String()))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" aria-label=\"breadcrumbs\" itemprop=\"breadcrumb\" itemtype=\"https://schema.org/BreadcrumbList\" itemscope><ol class=\"breadcrumb\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = breadcrumbsItem("Курсы", "/courses", params.ActiveLearningType.Empty()).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if !params.ActiveLearningType.Empty() {
templ_7745c5c3_Err = breadcrumbsItem(
params.ActiveLearningType.Name,
path.Join("/", "courses", params.ActiveLearningType.ID),
params.ActiveCourseThematic.Empty(),
).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
if !params.ActiveCourseThematic.Empty() {
templ_7745c5c3_Err = breadcrumbsItem(
params.ActiveCourseThematic.Name,
path.Join("/", "courses", params.ActiveLearningType.ID, params.ActiveCourseThematic.ID),
true,
).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</ol></nav>") _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</ol></nav>")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
@ -154,3 +191,567 @@ func breadcrumNode(params BreadcrumbsParams) templ.Component {
return templ_7745c5c3_Err return templ_7745c5c3_Err
}) })
} }
func breadcrumbSymbol() templ.CSSClass {
var templ_7745c5c3_CSSBuilder strings.Builder
templ_7745c5c3_CSSBuilder.WriteString(`--bs-breadcrumb-divider:"/";`)
templ_7745c5c3_CSSID := templ.CSSID(`breadcrumbSymbol`, templ_7745c5c3_CSSBuilder.String())
return templ.ComponentCSSClass{
ID: templ_7745c5c3_CSSID,
Class: templ.SafeCSS(`.` + templ_7745c5c3_CSSID + `{` + templ_7745c5c3_CSSBuilder.String() + `}`),
}
}
func listCoursesSectionHeader(params BreadcrumbsParams) templ.Component {
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
if !templ_7745c5c3_IsBuffer {
templ_7745c5c3_Buffer = templ.GetBuffer()
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var8 := templ.GetChildren(ctx)
if templ_7745c5c3_Var8 == nil {
templ_7745c5c3_Var8 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<section class=\"row bc-header\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = breadcrumNode(params).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</section>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if !templ_7745c5c3_IsBuffer {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
}
return templ_7745c5c3_Err
})
}
func listCoursesSectionFilters(params FilterFormParams) templ.Component {
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
if !templ_7745c5c3_IsBuffer {
templ_7745c5c3_Buffer = templ.GetBuffer()
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var9 := templ.GetChildren(ctx)
if templ_7745c5c3_Var9 == nil {
templ_7745c5c3_Var9 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<section class=\"row filters\"><div class=\"col-8\"><form id=\"filter-form\" class=\"input-group\"><span class=\"input-group-text\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Var10 := `Filter courses`
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var10)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</span> ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var11 = []any{"form-select"}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var11...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<select id=\"learning-type-filter\" class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ.CSSClasses(templ_7745c5c3_Var11).String()))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"><option")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if params.ActiveLearningType.ID == "" {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" selected")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Var12 := `All`
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var12)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</option> ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
for _, learningType := range params.AvailableLearningTypes {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<option")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if params.ActiveLearningType.ID == learningType.ID {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" selected")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(learningType.ID))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var13 string
templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(learningType.Name)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/kurious/ports/http/bootstrap/list.templ`, Line: 96, Col: 25}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</option>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</select> ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var14 = []any{"form-select", templ.KV("d-none", len(params.AvailableCourseThematics) == 0)}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var14...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<select id=\"course-thematic-filter\" class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ.CSSClasses(templ_7745c5c3_Var14).String()))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"><option")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if params.ActiveLearningType.ID == "" {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" selected")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Var15 := `All`
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var15)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</option> ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
for _, courseThematic := range params.AvailableCourseThematics {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<option")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if params.ActiveCourseThematic.ID == courseThematic.ID {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" selected")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(courseThematic.ID))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var16 string
templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(courseThematic.Name)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/kurious/ports/http/bootstrap/list.templ`, Line: 109, Col: 27}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</option>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</select> <button class=\"btn btn-outline-secondary\" type=\"button\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Var17 := `Go`
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var17)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</button></form></div></section>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if !templ_7745c5c3_IsBuffer {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
}
return templ_7745c5c3_Err
})
}
func listCoursesLearning(containers []CategoryContainer) templ.Component {
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
if !templ_7745c5c3_IsBuffer {
templ_7745c5c3_Buffer = templ.GetBuffer()
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var18 := templ.GetChildren(ctx)
if templ_7745c5c3_Var18 == nil {
templ_7745c5c3_Var18 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
for _, container := range containers {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<section class=\"row first-class-group\"><h1 class=\"title\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var19 string
templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(container.Name)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/kurious/ports/http/bootstrap/list.templ`, Line: 121, Col: 36}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</h1><p>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var20 string
templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(container.Description)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/kurious/ports/http/bootstrap/list.templ`, Line: 122, Col: 28}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</p><div class=\"block\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Var21 := `Placeholder for filter`
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var21)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
for _, subcategory := range container.Subcategories {
templ_7745c5c3_Err = listCoursesThematicRow(subcategory).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</section>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
if !templ_7745c5c3_IsBuffer {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
}
return templ_7745c5c3_Err
})
}
func listCoursesThematicRow(subcategory SubcategoryContainer) templ.Component {
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
if !templ_7745c5c3_IsBuffer {
templ_7745c5c3_Buffer = templ.GetBuffer()
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var22 := templ.GetChildren(ctx)
if templ_7745c5c3_Var22 == nil {
templ_7745c5c3_Var22 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"block second-class-group\"><h2 class=\"title\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var23 string
templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.JoinStringErrs(subcategory.Name)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/kurious/ports/http/bootstrap/list.templ`, Line: 135, Col: 37}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var23))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</h2><p>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var24 string
templ_7745c5c3_Var24, templ_7745c5c3_Err = templ.JoinStringErrs(subcategory.Description)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/kurious/ports/http/bootstrap/list.templ`, Line: 136, Col: 29}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var24))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</p><div class=\"row g-4\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
for _, info := range subcategory.Courses {
templ_7745c5c3_Err = listCoursesCard(info).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if !templ_7745c5c3_IsBuffer {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
}
return templ_7745c5c3_Err
})
}
func myImg() templ.CSSClass {
var templ_7745c5c3_CSSBuilder strings.Builder
templ_7745c5c3_CSSBuilder.WriteString(`min-height:19rem;`)
templ_7745c5c3_CSSBuilder.WriteString(`min-width:19rem;`)
templ_7745c5c3_CSSID := templ.CSSID(`myImg`, templ_7745c5c3_CSSBuilder.String())
return templ.ComponentCSSClass{
ID: templ_7745c5c3_CSSID,
Class: templ.SafeCSS(`.` + templ_7745c5c3_CSSID + `{` + templ_7745c5c3_CSSBuilder.String() + `}`),
}
}
func cardTextSize() templ.CSSClass {
var templ_7745c5c3_CSSBuilder strings.Builder
templ_7745c5c3_CSSBuilder.WriteString(`min-height:16rem;`)
templ_7745c5c3_CSSID := templ.CSSID(`cardTextSize`, templ_7745c5c3_CSSBuilder.String())
return templ.ComponentCSSClass{
ID: templ_7745c5c3_CSSID,
Class: templ.SafeCSS(`.` + templ_7745c5c3_CSSID + `{` + templ_7745c5c3_CSSBuilder.String() + `}`),
}
}
func listCoursesCard(info CourseInfo) templ.Component {
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
if !templ_7745c5c3_IsBuffer {
templ_7745c5c3_Buffer = templ.GetBuffer()
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var25 := templ.GetChildren(ctx)
if templ_7745c5c3_Var25 == nil {
templ_7745c5c3_Var25 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"col-12 col-md-6 col-lg-3\"><div class=\"card\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var26 = []any{"card-img-top", myImg()}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var26...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<img src=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(GetOrFallback(info.ImageLink, "https://placehold.co/128x128")))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" alt=\"Course picture\" class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ.CSSClasses(templ_7745c5c3_Var26).String()))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var27 = []any{"card-body", cardTextSize()}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var27...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ.CSSClasses(templ_7745c5c3_Var27).String()))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"><h5 class=\"card-title\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var28 string
templ_7745c5c3_Var28, templ_7745c5c3_Err = templ.JoinStringErrs(info.Name)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/kurious/ports/http/bootstrap/list.templ`, Line: 161, Col: 38}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var28))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</h5><div class=\"input-group d-flex\"><a href=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var29 templ.SafeURL = templ.URL(info.OriginLink)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var29)))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" class=\"btn text btn-outline-primary flex-grow-1\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Var30 := `Go!`
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var30)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a> <span class=\"input-group-text justify-content-end flex-fill\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var31 string
templ_7745c5c3_Var31, templ_7745c5c3_Err = templ.JoinStringErrs(strconv.Itoa(info.FullPrice))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/kurious/ports/http/bootstrap/list.templ`, Line: 168, Col: 36}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var31))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Var32 := `rub.`
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var32)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</span></div></div></div></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if !templ_7745c5c3_IsBuffer {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
}
return templ_7745c5c3_Err
})
}
func ListCourses(pageType PageKind, s stats, params ListCoursesParams) templ.Component {
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
if !templ_7745c5c3_IsBuffer {
templ_7745c5c3_Buffer = templ.GetBuffer()
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var33 := templ.GetChildren(ctx)
if templ_7745c5c3_Var33 == nil {
templ_7745c5c3_Var33 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Var34 := templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
if !templ_7745c5c3_IsBuffer {
templ_7745c5c3_Buffer = templ.GetBuffer()
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
}
templ_7745c5c3_Err = listCoursesSectionHeader(params.FilterForm.BreadcrumbsParams).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = listCoursesSectionFilters(params.FilterForm).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = listCoursesLearning(params.Categories).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if !templ_7745c5c3_IsBuffer {
_, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer)
}
return templ_7745c5c3_Err
})
templ_7745c5c3_Err = root(pageType, s).Render(templ.WithChildren(ctx, templ_7745c5c3_Var34), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if !templ_7745c5c3_IsBuffer {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
}
return templ_7745c5c3_Err
})
}

View File

@ -5,6 +5,14 @@ import (
"strings" "strings"
) )
type PageKind string
const (
PageIndex PageKind = "main"
PageCourses PageKind = "courses"
PageAbout PageKind = "about"
)
func getCompactedValue(value int) string { func getCompactedValue(value int) string {
var ( var (
myValue float64 myValue float64
@ -58,10 +66,6 @@ type FilterFormParams struct {
AvailableCourseThematics []Category AvailableCourseThematics []Category
} }
func isEmpty(s string) bool {
return s == ""
}
type CourseInfo struct { type CourseInfo struct {
ID string ID string
Name string Name string
@ -93,3 +97,11 @@ type ListCoursesParams struct {
Categories []CategoryContainer Categories []CategoryContainer
} }
func GetOrFallback[T comparable](value T, fallback T) T {
var zeroValue T
if value == zeroValue {
return fallback
}
return value
}

View File

@ -7,6 +7,7 @@ import (
"git.loyso.art/frx/kurious/internal/common/xslices" "git.loyso.art/frx/kurious/internal/common/xslices"
"git.loyso.art/frx/kurious/internal/kurious/app/query" "git.loyso.art/frx/kurious/internal/kurious/app/query"
"git.loyso.art/frx/kurious/internal/kurious/domain" "git.loyso.art/frx/kurious/internal/kurious/domain"
"git.loyso.art/frx/kurious/internal/kurious/ports/http/bootstrap"
xtempl "git.loyso.art/frx/kurious/internal/kurious/ports/http/templ" xtempl "git.loyso.art/frx/kurious/internal/kurious/ports/http/templ"
"git.loyso.art/frx/kurious/internal/kurious/service" "git.loyso.art/frx/kurious/internal/kurious/service"
) )
@ -72,6 +73,8 @@ func makeTemplListCoursesParams(in ...domain.Course) xtempl.ListCoursesParams {
return out return out
} }
const useBootstrap = true
func (c courseTemplServer) List(w http.ResponseWriter, r *http.Request) { func (c courseTemplServer) List(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
@ -105,7 +108,7 @@ func (c courseTemplServer) List(w http.ResponseWriter, r *http.Request) {
Name: in.Name, Name: in.Name,
} }
if in.ID == pathParams.learningType { if in.ID == pathParams.learningType {
params.FilterForm.BreadcrumbsParams.ActiveLearningType = outcategory params.FilterForm.ActiveLearningType = outcategory
} }
return outcategory return outcategory
@ -132,7 +135,48 @@ func (c courseTemplServer) List(w http.ResponseWriter, r *http.Request) {
}) })
} }
err = xtempl.ListCourses(stats, params).Render(ctx, w) if useBootstrap {
c.log.DebugContext(
ctx, "using bootstrap",
slog.Int("course_thematic", len(params.FilterForm.AvailableCourseThematics)),
slog.Int("learning_type", len(params.FilterForm.AvailableLearningTypes)),
)
mapCategory := func(in xtempl.Category) bootstrap.Category {
return bootstrap.Category(in)
}
mapCourseInfo := func(in xtempl.CourseInfo) bootstrap.CourseInfo {
return bootstrap.CourseInfo(in)
}
mapSubcategoryContainer := func(in xtempl.SubcategoryContainer) bootstrap.SubcategoryContainer {
return bootstrap.SubcategoryContainer{
CategoryBaseInfo: bootstrap.CategoryBaseInfo(in.CategoryBaseInfo),
Courses: xslices.Map(in.Courses, mapCourseInfo),
}
}
mapCategoryContainer := func(in xtempl.CategoryContainer) bootstrap.CategoryContainer {
return bootstrap.CategoryContainer{
CategoryBaseInfo: bootstrap.CategoryBaseInfo(in.CategoryBaseInfo),
Subcategories: xslices.Map(in.Subcategories, mapSubcategoryContainer),
}
}
stats := bootstrap.MakeNewStats(0, 0, 0)
params := bootstrap.ListCoursesParams{
FilterForm: bootstrap.FilterFormParams{
BreadcrumbsParams: bootstrap.BreadcrumbsParams{
ActiveLearningType: bootstrap.Category(params.FilterForm.ActiveLearningType),
ActiveCourseThematic: bootstrap.Category(params.FilterForm.ActiveCourseThematic),
},
AvailableLearningTypes: xslices.Map(params.FilterForm.AvailableLearningTypes, mapCategory),
AvailableCourseThematics: xslices.Map(params.FilterForm.AvailableCourseThematics, mapCategory),
},
Categories: xslices.Map(params.Categories, mapCategoryContainer),
}
err = bootstrap.ListCourses(bootstrap.PageCourses, stats, params).Render(ctx, w)
} else {
err = xtempl.ListCourses(stats, params).Render(ctx, w)
}
if handleError(ctx, err, w, c.log, "unable to render list courses") { if handleError(ctx, err, w, c.log, "unable to render list courses") {
return return
} }