Current state of porting to a Templ template engine. Stage 2.
This commit is contained in:
parent
77aa7a5e63
commit
89de89671a
@ -37,31 +37,29 @@ func NewHandlers(captchaExpire time.Duration, owner string, gbPageSize int64,
|
||||
}
|
||||
|
||||
func (h *Handlers) Privacy(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
web.Privacy("/ Privacy statements",
|
||||
util.GetServiceByHost(r.Host, util.ServiceRadio),
|
||||
util.GetServiceByHost(r.Host, util.ServiceRadio),
|
||||
util.GetServiceByHost(r.Host, util.ServiceUpload), w)
|
||||
web.Privacy(r).Render(context.Background(), w)
|
||||
}
|
||||
|
||||
func (h *Handlers) Stuff(w http.ResponseWriter, r *http.Request) {
|
||||
web.Stuff("/ Stuff", util.GetServiceByHost(r.Host, util.ServiceGit),
|
||||
util.GetServiceByHost(r.Host, util.ServiceFiles), web.Metadata, w)
|
||||
web.Stuff(r).Render(context.Background(), w)
|
||||
}
|
||||
|
||||
func (h *Handlers) Mindflow(w http.ResponseWriter, r *http.Request) {
|
||||
posts, err := h.mindflowDB.Posts()
|
||||
if err != nil {
|
||||
log.Println("Cannot load posts.", err)
|
||||
Error(w, http.StatusInternalServerError, "Cannot load posts.", "", r.Referer())
|
||||
return
|
||||
}
|
||||
|
||||
categories, err := h.mindflowDB.Categories()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
log.Println("Cannot load categories.", err)
|
||||
Error(w, http.StatusInternalServerError, "Cannot load categories.", "", r.Referer())
|
||||
return
|
||||
}
|
||||
|
||||
web.Mindflow("/ Mindflow", posts, categories, r, w)
|
||||
web.Mindflow(posts, categories, r).Render(context.Background(), w)
|
||||
}
|
||||
|
||||
func (h *Handlers) MindflowAdmin(w http.ResponseWriter, r *http.Request) {
|
||||
@ -77,7 +75,7 @@ func (h *Handlers) MindflowAdmin(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
web.MindflowAdmin("/ Mindflow Administration", posts, categories, r, w)
|
||||
web.MindflowAdmin(posts, categories, r).Render(context.Background(), w)
|
||||
}
|
||||
|
||||
func (h *Handlers) About(w http.ResponseWriter, r *http.Request) {
|
||||
@ -95,18 +93,18 @@ func (h *Handlers) About(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
web.About("/ About", util.GetServiceByHost(r.Host, util.ServiceFiles), lst, w)
|
||||
web.About(util.GetServiceByHost(r.Host, util.ServiceFiles), lst).Render(context.Background(), w)
|
||||
}
|
||||
|
||||
func (h *Handlers) Article(w http.ResponseWriter, r *http.Request) {
|
||||
name := r.URL.Path[strings.LastIndex(r.URL.Path, "/")+1:]
|
||||
artcl := web.GetArticle(name)
|
||||
if artcl == nil {
|
||||
http.Error(w, "an article doesn't exist", http.StatusNotFound)
|
||||
Error(w, http.StatusNotFound, "", "An article \""+name+"\" doesn't exist.", r.Referer())
|
||||
return
|
||||
}
|
||||
|
||||
web.Article(artcl.Title, artcl.Description, string(artcl.Body), artcl.Date, r.Host, name, r, w)
|
||||
web.Article(artcl.Title, artcl.Description, string(artcl.Body), name, artcl.Date, r).Render(context.Background(), w)
|
||||
}
|
||||
|
||||
func (h *Handlers) Guestbook(w http.ResponseWriter, r *http.Request) {
|
||||
@ -157,7 +155,7 @@ func (h *Handlers) GuestbookAdmin(w http.ResponseWriter, r *http.Request) {
|
||||
entry.Message = strings.ReplaceAll(entry.Message, "\\n", "\n")
|
||||
}
|
||||
|
||||
web.GuestbookAdmin("/ Guestbook Administration", h.owner, entries, r, w)
|
||||
web.GuestbookAdmin(h.owner, entries, r).Render(context.Background(), w)
|
||||
}
|
||||
|
||||
func (h *Handlers) RSS(w http.ResponseWriter, r *http.Request) {
|
||||
|
11
web/about.templ
Normal file
11
web/about.templ
Normal file
@ -0,0 +1,11 @@
|
||||
package web
|
||||
|
||||
import "git.arav.su/Arav/dwelling-home/pkg/servicestat"
|
||||
|
||||
templ About(filesSrvc string, services servicestat.ServiceList) {
|
||||
@base("About", "About me and my home servers.", "about, me, servcies", "/about", "About", aboutHead())
|
||||
}
|
||||
|
||||
templ aboutHead() {
|
||||
<link rel="stylesheet" href="/assets/css/about.css"/>
|
||||
}
|
26
web/article.templ
Normal file
26
web/article.templ
Normal file
@ -0,0 +1,26 @@
|
||||
package web
|
||||
|
||||
import "time"
|
||||
import "net/http"
|
||||
|
||||
import "git.arav.su/Arav/dwelling-home/pkg/util"
|
||||
|
||||
templ Article(title, description, body, urlName string, date time.Time, r *http.Request) {
|
||||
@base(title + " - Articles", description, "", "/stuff/article/"+urlName, "Articles", articleHead()) {
|
||||
<article>
|
||||
<header>
|
||||
<h2>{ title }</h2>
|
||||
<div class="menu">
|
||||
<a href="/stuff#articles">Go back to articles list</a>
|
||||
{{ dctz := util.ToClientTimezone(date, r) }}
|
||||
<time datetime={ dctz.Format("2006-01-02") }>{ dctz.Format("02 January 2006") }</time>
|
||||
</div>
|
||||
</header>
|
||||
@templ.Raw(body)
|
||||
</article>
|
||||
}
|
||||
}
|
||||
|
||||
templ articleHead() {
|
||||
<link rel="stylesheet" href="/assets/css/articles.css"/>
|
||||
}
|
@ -4,4 +4,8 @@
|
||||
text-align: center;
|
||||
margin: 6rem 0; }
|
||||
|
||||
#error h1 { font-size: 8rem; }
|
||||
#error h1 { font-size: 8rem; }
|
||||
|
||||
#error p {
|
||||
font-size: 1.1rem;
|
||||
text-align: center; }
|
@ -58,6 +58,8 @@ button.refresh:disabled {
|
||||
text-align: center;
|
||||
width: 4.5rem; }
|
||||
|
||||
article p { white-space: pre; }
|
||||
|
||||
input[type="submit"] {
|
||||
background-color: var(--primary-color);
|
||||
border: none;
|
||||
|
103
web/base.templ
103
web/base.templ
@ -1,59 +1,64 @@
|
||||
package web
|
||||
|
||||
import "strings"
|
||||
// import "strings"
|
||||
|
||||
templ base(title, description, keywords, canonical, heading string, head templ.Component) {
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
if title != "" {
|
||||
<title>{ title } - Arav's dwelling</title>
|
||||
} else {
|
||||
<title>Arav's dwelling</title>
|
||||
}
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="theme-color" content="#cd2682" />
|
||||
<meta name="description" content={ description } />
|
||||
<meta name="keywords" content={ keywords } />
|
||||
<link rel="icon" href="/assets/img/favicon.svg" sizes="any" type="image/svg+xml" />
|
||||
<link rel="stylesheet" href="/assets/css/main.css" />
|
||||
<link rel="alternate" href="/rss.xml" type="application/rss+xml" title="Arav's dwelling" />
|
||||
<link rel="canonical" href={ string(templ.URL(canonical)) }/>
|
||||
@head
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<svg id="logo" viewBox="0 -25 216 40">
|
||||
<text class="logo">Arav's dwelling</text>
|
||||
<text class="under" y="11">Welcome to my sacred place, wanderer</text>
|
||||
</svg>
|
||||
<nav>
|
||||
@navigation(heading)
|
||||
</nav>
|
||||
</header>
|
||||
{ children... }
|
||||
<footer>
|
||||
<a href="/rss.xml" title="Stay up to date on what's going on.">RSS feed</a>
|
||||
<br>
|
||||
© 2017—2024 Alexander "Arav" Andreev <<a href="mailto:me@arav.su">me@arav.su</a>> <a href="/privacy">Privacy statements</a>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
if title != "" {
|
||||
<title>{ title } - Arav's dwelling</title>
|
||||
} else {
|
||||
<title>Arav's dwelling</title>
|
||||
}
|
||||
<meta charset="utf-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<meta name="theme-color" content="#cd2682"/>
|
||||
<meta name="description" content={ description }/>
|
||||
<meta name="keywords" content={ keywords }/>
|
||||
<link rel="icon" href="/assets/img/favicon.svg" sizes="any" type="image/svg+xml"/>
|
||||
<link rel="stylesheet" href="/assets/css/main.css"/>
|
||||
<link rel="alternate" href="/rss.xml" type="application/rss+xml" title="Arav's dwelling"/>
|
||||
if canonical != "" {
|
||||
<link rel="canonical" href={ string(templ.URL(canonical)) }/>
|
||||
}
|
||||
if head != nil {
|
||||
@head
|
||||
}
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<svg id="logo" viewBox="0 -25 216 40">
|
||||
<text class="logo">Arav's dwelling</text>
|
||||
<text class="under" y="11">Welcome to my sacred place, wanderer</text>
|
||||
</svg>
|
||||
@navigation(heading)
|
||||
</header>
|
||||
{ children... }
|
||||
<footer>
|
||||
<a href="/rss.xml" title="Stay up to date on what's going on.">RSS feed</a>
|
||||
<br/>
|
||||
© 2017—2024 Alexander "Arav" Andreev <<a href="mailto:me@arav.su">me@arav.su</a>> <a href="/privacy">Privacy statements</a>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
}
|
||||
|
||||
var navElements = []string{"Stuff", "Mindflow", "About", "Guestbook"}
|
||||
|
||||
templ navigation(heading string) {
|
||||
for _, n := range navElements {
|
||||
if n == heading {
|
||||
continue
|
||||
}
|
||||
<a href={ templ.SafeURL("/" + strings.ToLower(n)) }>{ n }</a>
|
||||
}
|
||||
<nav>
|
||||
if heading != "Home" {
|
||||
<a href="/">Home</a>
|
||||
}
|
||||
<a href="/stuff">Stuff</a>
|
||||
<a href="/mindflow">Mindflow</a>
|
||||
<a href="/about">About</a>
|
||||
<a href="/guestbook">Guestbook</a>
|
||||
|
||||
if heading != "" {
|
||||
<h1>{ heading }</h1>
|
||||
}
|
||||
}
|
||||
if heading != "" && heading != "Home" {
|
||||
<h1>{ heading }</h1>
|
||||
}
|
||||
</nav>
|
||||
}
|
||||
|
@ -4,23 +4,26 @@ import "fmt"
|
||||
import "net/http"
|
||||
|
||||
templ ErrorXXX(errCode int, reason, message, referer string) {
|
||||
{{ errText := http.StatusText(errCode) }}
|
||||
@base(errText, errText,
|
||||
"", "", errText, nil) {
|
||||
<section id="error">
|
||||
<h1>{ fmt.Sprint(errCode) }</h1>
|
||||
{ errText }
|
||||
if reason != "" {
|
||||
<p>{ reason }</p>
|
||||
}
|
||||
if message != "" {
|
||||
<p>{ message }</p>
|
||||
}
|
||||
</section>
|
||||
if referer != "" {
|
||||
<section>
|
||||
<h2><a href={ templ.URL(referer) }>Go back</a></h2>
|
||||
</section>
|
||||
}
|
||||
{{ errText := http.StatusText(errCode) }}
|
||||
@base(errText, errText, "", "", errText, errorXXXHead()) {
|
||||
<section id="error">
|
||||
<h1>{ fmt.Sprint(errCode) }</h1>
|
||||
{ errText }
|
||||
if reason != "" {
|
||||
<p>{ reason }</p>
|
||||
}
|
||||
if message != "" {
|
||||
<p>{ message }</p>
|
||||
}
|
||||
</section>
|
||||
if referer != "" {
|
||||
<section>
|
||||
<h2><a href={ templ.URL(referer) }>Go back</a></h2>
|
||||
</section>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
templ errorXXXHead() {
|
||||
<link rel="stylesheet" href="/assets/css/error.css">
|
||||
}
|
@ -10,79 +10,81 @@ import "git.arav.su/Arav/justguestbook"
|
||||
import "git.arav.su/Arav/dwelling-home/pkg/util"
|
||||
|
||||
templ Guestbook(captchaID, owner string, entries []*justguestbook.Entry, pageCount int64, r *http.Request) {
|
||||
@base("Guestbook",
|
||||
"This is my guestbook. Welcome.",
|
||||
"guestbook, personal", "/guestbook", "Guestbook", guestbookHead()) {
|
||||
<form id="new-post" action="/api/guestbook" method="POST">
|
||||
<input type="text" name="name" maxlength="80" placeholder="Name (Anonymous if left blank)" />
|
||||
<input type="text" name="website" maxlength="255" placeholder="Website (optional)" />
|
||||
<textarea name="message" maxlength="4096" placeholder="Your message" required></textarea>
|
||||
<span class="checkboxes">
|
||||
<input type="checkbox" name="hide_website" id="hide-website" checked />
|
||||
<label for="hide-website">Hide website <small>(only I can see if set)</small></label>
|
||||
<br>
|
||||
<small>Use > to make a quote.</small>
|
||||
</span>
|
||||
<span class="captcha">
|
||||
<input type="hidden" name="captcha_id" value={ captchaID } />
|
||||
<img src={ string(templ.URL(fmt.Sprintf("/api/captcha/%s/image", captchaID))) } alt="CAPTCHA" width="160" height="40" />
|
||||
<input type="text" name="captcha_answer" maxlength="6" placeholder="CAPTCHA" required />
|
||||
<small>Valid for <b>10</b> minutes.</small>
|
||||
</span>
|
||||
<input type="submit" value="Send a post" />
|
||||
</form>
|
||||
<section id="posts">
|
||||
for _, entry := range entries {
|
||||
<article>
|
||||
<header>
|
||||
{{ created_tz := util.ToClientTimezone(entry.Created, r).Format("Monday _2 January 2006 15:04:05 -07:00") }}
|
||||
{{ website := "" }}
|
||||
if !entry.HideWebsite {
|
||||
{{ website = entry.Website }}
|
||||
}
|
||||
{ strconv.FormatInt(entry.ID, 10) } by <span class="highlighted">{ entry.Name }</span> <em>{ website }</em> on <time datetime={ created_tz }>{ created_tz }</time>
|
||||
</header>
|
||||
for _, line := range strings.Split(entry.Message, "\n") {
|
||||
if len(line) > 0 && line[0] == '>' {
|
||||
<p class="quote">{ line }</p>
|
||||
} else {
|
||||
<p>{ line }</p>
|
||||
}
|
||||
}
|
||||
if entry.Reply != nil {
|
||||
<div class="reply">
|
||||
<header>
|
||||
{{ reply_created_tz := util.ToClientTimezone(entry.Reply.Created, r).Format("Monday _2 January 2006 15:04:05 -07:00") }}
|
||||
Reply by <span class="highlighted">{ owner }</span> in <time datetime={ reply_created_tz }>{ reply_created_tz }</time>
|
||||
</header>
|
||||
for _, line := range strings.Split(entry.Reply.Message, "\n") {
|
||||
if len(line) > 0 && line[0] == '>' {
|
||||
<p class="quote">{ line }</p>
|
||||
} else {
|
||||
<p>{ line }</p>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</article>
|
||||
}
|
||||
if len(entries) == 0 {
|
||||
<p class="center">No posts.</p>
|
||||
}
|
||||
</section>
|
||||
if pageCount > 1 {
|
||||
<section id="pagination">
|
||||
{{ var n int64 = 1 }}
|
||||
for ; n <= pageCount; n++ {
|
||||
{{ strN := strconv.FormatInt(n, 10) }}
|
||||
<a href={ templ.URL("/guestbook?p="+strN) }>{ strN }</a>
|
||||
}
|
||||
</section>
|
||||
}
|
||||
}
|
||||
@base("Guestbook", "This is my guestbook. Welcome.", "guestbook, personal", "/guestbook", "Guestbook", guestbookHead()) {
|
||||
<form id="new-post" action="/api/guestbook" method="POST">
|
||||
<input type="text" name="name" maxlength="80" placeholder="Name (Anonymous if left blank)"/>
|
||||
<input type="text" name="website" maxlength="255" placeholder="Website (optional)"/>
|
||||
<textarea name="message" maxlength="4096" placeholder="Your message" required></textarea>
|
||||
<span class="checkboxes">
|
||||
<input type="checkbox" name="hide_website" id="hide-website" checked/>
|
||||
<label for="hide-website">Hide website <small>(only I can see if set)</small></label>
|
||||
<br/>
|
||||
<small>Use > to make a quote.</small>
|
||||
</span>
|
||||
<span class="captcha">
|
||||
<input type="hidden" name="captcha_id" value={ captchaID }/>
|
||||
<img src={ string(templ.URL(fmt.Sprintf("/api/captcha/%s/image", captchaID))) } alt="CAPTCHA" width="160" height="40"/>
|
||||
<input type="text" name="captcha_answer" maxlength="6" placeholder="CAPTCHA" required/>
|
||||
<small>Valid for <b>10</b> minutes.</small>
|
||||
</span>
|
||||
<input type="submit" value="Send a post"/>
|
||||
</form>
|
||||
<section id="posts">
|
||||
for _, entry := range entries {
|
||||
<article>
|
||||
<header>
|
||||
{{ created_tz := util.ToClientTimezone(entry.Created, r).Format("Monday _2 January 2006 15:04:05 -07:00") }}
|
||||
{{ website := "" }}
|
||||
if !entry.HideWebsite {
|
||||
{{ website = entry.Website }}
|
||||
}
|
||||
{ strconv.FormatInt(entry.ID, 10) } by <span class="highlighted">{ entry.Name }</span> <em>{ website }</em> on <time datetime={ created_tz }>{ created_tz }</time>
|
||||
</header>
|
||||
for _, line := range strings.Split(entry.Message, "\n") {
|
||||
if len(line) > 0 && line[0] == '>' {
|
||||
<p class="quote">@templ.Raw(line)
|
||||
</p>
|
||||
} else {
|
||||
<p>@templ.Raw(line)
|
||||
</p>
|
||||
}
|
||||
}
|
||||
if entry.Reply != nil {
|
||||
<div class="reply">
|
||||
<header>
|
||||
{{ reply_created_tz := util.ToClientTimezone(entry.Reply.Created, r).Format("Monday _2 January 2006 15:04:05 -07:00") }}
|
||||
Reply by <span class="highlighted">{ owner }</span> in <time datetime={ reply_created_tz }>{ reply_created_tz }</time>
|
||||
</header>
|
||||
for _, line := range strings.Split(entry.Reply.Message, "\n") {
|
||||
if len(line) > 0 && line[0] == '>' {
|
||||
<p class="quote">@templ.Raw(line)
|
||||
</p>
|
||||
} else {
|
||||
<p>@templ.Raw(line)
|
||||
</p>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</article>
|
||||
}
|
||||
if len(entries) == 0 {
|
||||
<p class="center">No posts.</p>
|
||||
}
|
||||
</section>
|
||||
if pageCount > 1 {
|
||||
<section id="pagination">
|
||||
{{ var n int64 = 1 }}
|
||||
for ; n <= pageCount; n++ {
|
||||
{{ strN := strconv.FormatInt(n, 10) }}
|
||||
<a href={ templ.URL("/guestbook?p=" + strN) }>{ strN }</a>
|
||||
}
|
||||
</section>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
templ guestbookHead() {
|
||||
<link rel="stylesheet" href="/assets/css/guestbook.css" />
|
||||
<script src="/assets/js/captcha_refresh.js" defer></script>
|
||||
}
|
||||
<link rel="stylesheet" href="/assets/css/guestbook.css"/>
|
||||
<script src="/assets/js/captcha_refresh.js" defer></script>
|
||||
}
|
||||
|
9
web/guestbook_admin.templ
Normal file
9
web/guestbook_admin.templ
Normal file
@ -0,0 +1,9 @@
|
||||
package web
|
||||
|
||||
import "net/http"
|
||||
|
||||
import "git.arav.su/Arav/justguestbook"
|
||||
|
||||
templ GuestbookAdmin(owner string, entries []*justguestbook.Entry, r *http.Request) {
|
||||
@base("Guestbook Administration", "", "", "/guestbook/admin", "Guestbook Administration", nil)
|
||||
}
|
@ -1,67 +1,36 @@
|
||||
package web
|
||||
|
||||
templ Index() {
|
||||
@base("",
|
||||
"A homepage of a russian guy Alexander aka Arav. Not just homepage, but something more...", "/",
|
||||
"homepage, personal, blog, services, self-hosting", "", nil) {
|
||||
<section id="services">
|
||||
<span>
|
||||
<a href="https://arav.su">arav.su</a>
|
||||
.
|
||||
<a href="http://moq7aejnf4xk5k2bkaltli3ftkhusy2mbrd3pj23nrca343ku2mgk4yd.onion">onion</a>
|
||||
.
|
||||
<a href="http://[300:a98d:d6d0:8a08::f]">ygg</a>
|
||||
.
|
||||
<a href="http://arav.i2p">i2p</a>
|
||||
<sup><a href="http://arav.i2p/?i2paddresshelper=5Kl-DiWbbk6wf7m0v6zBSNHYq3sXlnrWLIWVeGdpPbPyc9CBS~zrzDYpP43rv1fRiIkbVCD5hTEpY6joQGlk-dFkWWD6201qa6ecsDVQMaE3Q7UTYICd0VEBRoqDUSrvsM-P2y5oG4Z-77RmoGKpbcRgNuMVbQ7AGJNqVSGej-lSyscDWTIZT5dCT505lfRwprdD~emZqkwnn22X16Wpj-X4A4ifph4idrThGioz4UW6PrCpa-oebMCo217s0Zyl9VKaU-o9cx5eFUEwnshoUjqwh7VE-S45NDz854J08xldCATM3wwTRVXhc2NUypsJLKFKiV0z3EXN-ApCdxsV60C-eiXUTX5vYcHHH~imA79v8WKFybjnsyUBst5BBEPQIUifTceLUrTmQ9TUpaMV90EsD5SCshmCfOs8R5y2dK6EfQu8iyYAB5VFSH4M1CLiBZUsDTEFiOomn2JGMDnbPho8lMB8ss4SMuwZShb2LlGqLxJ38kRHlvC68VmJO7InBQAEAAcAAA==" title="Address helper">ah</a></sup>
|
||||
</span>
|
||||
<a href="https://arav.neocities.org">arav.neocities.org</a>
|
||||
<br>
|
||||
<span>
|
||||
<a href="https://radio.arav.su">radio</a>
|
||||
.
|
||||
<a href="http://wsmkgnmhmzqm7kyzv7jnzzafvgm7xlmlfvzhgorpapd5or2arnhuktqd.onion">onion</a>
|
||||
.
|
||||
<a href="http://[300:a98d:d6d0:8a08::e]">ygg</a>
|
||||
.
|
||||
<a href="http://radio.arav.i2p">i2p</a>
|
||||
<sup><a href="http://radio.arav.i2p/?i2paddresshelper=NfCKBu9vjLFiBMEPQGiZT9AzGlhkKHzYrKM66FL-ESeDbnYUY--NzukO9UA28s3WThhDQVge2TmyfYsaZiUw~AjuLsykxS13pebs7lkAVY1jm77La-eFFIAQ22Vtd2YgS0vbhRMzuDxKkCR1vPwNax8R2o6a07xsQvvDml6UQxG4p5vt44JA2geQNvQfm8cEiSa6gNJZJSW3rWuLDg6~1Jy3D70oSVSlNfihmG4JtNV6tVBjJE2h5gUxfhYZACttpGTPM~UNF~lrSujlBQsCqdzvLswdMw~FnvpfGzJcJroeFTerRyH6oUkkDSOK7uWwl0e70vKxrIbFgJjKtjlLWlUCI5N0TnJP4Hzt2pttB~R0hSr2vVl8ky0yJEtN3rwnrJkw7q0ZIH30ngTfxsCTbolAzl6liN9Ez5YF97zDOPnVFmvQ6Eg1PyFdypQO1PiUHqF56SWhx3utGwecUS6jJCvsKIJJVEIMVcD6h7S0z1g1rqQ4jbg5UfXPwFEgFOlzBQAEAAcAAA==" title="Address helper">ah</a></sup>
|
||||
</span>
|
||||
<span>
|
||||
<a href="https://files.arav.su">files</a>
|
||||
.
|
||||
<a href="http://qf5e43nlhvnrutmikuvbdfj3cmtthokpbaxtkm6mjlslttzvtgm4fxid.onion">onion</a>
|
||||
.
|
||||
<a href="http://[300:a98d:d6d0:8a08::e]">ygg</a>
|
||||
.
|
||||
<a href="http://files.arav.i2p">i2p</a>
|
||||
<sup><a href="http://files.arav.i2p/?i2paddresshelper=48vtYgeVnju7B2FaR0zxUL3MQXN9QjK~Ggya45aANwm86mtpemuEkaskJmEQaFSd4FcDAFIiXHfNpfGqoupLwNmtgBmGRcuVV8xb2W~W6lM0oOhovjB37EUaMWs3AI5aIES84QOqApgwYX-ANIcwa~Kg6AbMuX8D8qnejuhBbuCffYah-TD8e~O0cnyqxzLTmxIGCyk2egdYXwanJyYFDocomIVfcqfJ0MgjIHhFQtkcb0e84bxvDzcAFIpEDrzAo4GVrFn-TCu0Lyf2ccqmVpucFl0UGhuVRxEt19KLd3PxlfwHv2lmzTZtq9CbnfaoPntUPx1sf84QnZDmrXWhVK8p3VvuPZMxjyz9KyhPjrGkO4E0oibDlvKuMsGEm-GkZsKxgXo~CrdcVtN8suAwW6rACAuk8gq2jUMBZBZ12migPZ7miHftEkOFHfgfUiKBwirrw~y9Zi261WX4-EVe2oD4pkhQOrqOKIoI-vv5z9CpQ7PKL531kgkipcBseXybBQAEAAcAAA==" title="Address helper">ah</a></sup>
|
||||
</span>
|
||||
<span>
|
||||
<a href="https://upload.arav.su">upload</a>
|
||||
.
|
||||
<a href="http://4usftbmjpfexkr2x5xbp5ukmygpmg4fgrnx2wbifsexqctooz5hmviyd.onion">onion</a>
|
||||
.
|
||||
<a href="http://[300:a98d:d6d0:8a08::e]">ygg</a>
|
||||
.
|
||||
<a href="http://upload.arav.i2p">i2p</a>
|
||||
<sup><a href="http://upload.arav.i2p/?i2paddresshelper=b5NWA2vNydWSv6~8KN4e~td2UVGkYsayKPa1PnXI87A3gsg6m978tIehHLVN4XcCfUq4aB-59hqqZicorRnHKfV3lVdx9mdhC8Bhj~bMAcwMgWoXidqZNrWMoFGzWotFsa3nWh4zsRUSfrokecC8u9Y06byfSS1siyak0J6xpsggXRqqgNF0-8ncPeqvzBxHB9NRDXWEVJGS9HSpydWl1UpjgZffcd~NZroxkSAfughHcFAn2OLKkaZRe6WqCJQfJoXTCyz4wkFmYbH1CSddWlddmWaaU7icsbQrZm3XEqKTVKvm86G6ehxmzyHqCumc4GOWswcP0E51UQVOv-WA8R6SWQAj6ZnZhnCoCNFFEfW2lBiDmTnLJbfm-C-AdI6G1~dQ1~3FCH6wXWy-2DebpyoVVt9epzU7l4l2MVeaOUahbf6wcol1UbxPoR0XlGCXDe9700TYePjtpOU9vNkk2B1dQiZ1usgwseYuO26cRogSvbi8poz4BlCNO733HR1XBQAEAAcAAA==" title="Address helper">ah</a></sup>
|
||||
</span>
|
||||
<span>
|
||||
<a href="https://git.arav.su">git</a>
|
||||
.
|
||||
<a href="http://qqitm7qlsbbubwmjos4cqzmvkqidg34rfnbyhuydhalep33fbvh22xyd.onion">onion</a>
|
||||
.
|
||||
<a href="http://[300:a98d:d6d0:8a08::e]">ygg</a>
|
||||
.
|
||||
<a href="http://git.arav.i2p">i2p</a>
|
||||
<sup><a href="http://git.arav.i2p/?i2paddresshelper=eFIfcBUv3lHFSnglHfncs5XXtYwm9gCpmAYuio~9CeENBAXKRggPiY1tQC-otCon2hCSpr56WlVBeZk1txKuUnbjHTN7GBFaKW5wJEO2WmKEWPKdcjUDOYZN0D3TwXaYfiBuELD3200lBfDmPEJ01iC2o7B5yvpOqtEKDcaqkIp4vafDuPPumJ~XiCGdUAe~vr52w3Tbuz5x7wbltk-gUELY0-ZAQBos4jOJ6QT1W1lhycHPhAK8qslgwfk94opyIl2pkRyuJhU-2VHc6Fsd621VXC86YAMT1SIfTZlFpoGVCFXDM~BXaLvygFaKf62qardAe0T48Ax6GxosAKXe-yLCVRaiD3KErULfwZXl23kQzRfxM4odG4DWeXawtuvypOmTjHT1skQHU0h52ujye5nT~2bOy14HkCoCnxJ7gSj3MjkmWLd1JhBsPH4ymRmI7jFJR1GYl8Wp5IigMBBzWfJUEEjS7QDHaRo5TCZJ9SXz6sgkGdfh74~r8FWL559gBQAEAAcAAA==" title="Address helper">ah</a></sup>
|
||||
</span>
|
||||
</section>
|
||||
<section>
|
||||
<p>
|
||||
Welcome, Anon. I'm Alexander aka Arav, I self-host some services for myself, friends and you. Not much I have to offer, but maybe you'll find something useful for yourself. :)
|
||||
</p>
|
||||
</section>
|
||||
}
|
||||
}
|
||||
@base("",
|
||||
"A homepage of a russian guy Alexander aka Arav. Not just homepage, but something more...", "/",
|
||||
"homepage, personal, blog, services, self-hosting", "Home", indexHead()) {
|
||||
<section id="services">
|
||||
<span>
|
||||
<a href="https://arav.su">arav.su</a>.<a href="http://moq7aejnf4xk5k2bkaltli3ftkhusy2mbrd3pj23nrca343ku2mgk4yd.onion">onion</a>.<a href="http://[300:a98d:d6d0:8a08::f]">ygg</a>.<a href="http://arav.i2p">i2p</a><sup><a href="http://arav.i2p/?i2paddresshelper=5Kl-DiWbbk6wf7m0v6zBSNHYq3sXlnrWLIWVeGdpPbPyc9CBS~zrzDYpP43rv1fRiIkbVCD5hTEpY6joQGlk-dFkWWD6201qa6ecsDVQMaE3Q7UTYICd0VEBRoqDUSrvsM-P2y5oG4Z-77RmoGKpbcRgNuMVbQ7AGJNqVSGej-lSyscDWTIZT5dCT505lfRwprdD~emZqkwnn22X16Wpj-X4A4ifph4idrThGioz4UW6PrCpa-oebMCo217s0Zyl9VKaU-o9cx5eFUEwnshoUjqwh7VE-S45NDz854J08xldCATM3wwTRVXhc2NUypsJLKFKiV0z3EXN-ApCdxsV60C-eiXUTX5vYcHHH~imA79v8WKFybjnsyUBst5BBEPQIUifTceLUrTmQ9TUpaMV90EsD5SCshmCfOs8R5y2dK6EfQu8iyYAB5VFSH4M1CLiBZUsDTEFiOomn2JGMDnbPho8lMB8ss4SMuwZShb2LlGqLxJ38kRHlvC68VmJO7InBQAEAAcAAA==" title="Address helper">ah</a></sup>
|
||||
</span>
|
||||
<a href="https://arav.neocities.org">arav.neocities.org</a>
|
||||
<br/>
|
||||
<span>
|
||||
<a href="https://radio.arav.su">radio</a>.<a href="http://wsmkgnmhmzqm7kyzv7jnzzafvgm7xlmlfvzhgorpapd5or2arnhuktqd.onion">onion</a>.<a href="http://[300:a98d:d6d0:8a08::e]">ygg</a>.<a href="http://radio.arav.i2p">i2p</a><sup><a href="http://radio.arav.i2p/?i2paddresshelper=NfCKBu9vjLFiBMEPQGiZT9AzGlhkKHzYrKM66FL-ESeDbnYUY--NzukO9UA28s3WThhDQVge2TmyfYsaZiUw~AjuLsykxS13pebs7lkAVY1jm77La-eFFIAQ22Vtd2YgS0vbhRMzuDxKkCR1vPwNax8R2o6a07xsQvvDml6UQxG4p5vt44JA2geQNvQfm8cEiSa6gNJZJSW3rWuLDg6~1Jy3D70oSVSlNfihmG4JtNV6tVBjJE2h5gUxfhYZACttpGTPM~UNF~lrSujlBQsCqdzvLswdMw~FnvpfGzJcJroeFTerRyH6oUkkDSOK7uWwl0e70vKxrIbFgJjKtjlLWlUCI5N0TnJP4Hzt2pttB~R0hSr2vVl8ky0yJEtN3rwnrJkw7q0ZIH30ngTfxsCTbolAzl6liN9Ez5YF97zDOPnVFmvQ6Eg1PyFdypQO1PiUHqF56SWhx3utGwecUS6jJCvsKIJJVEIMVcD6h7S0z1g1rqQ4jbg5UfXPwFEgFOlzBQAEAAcAAA==" title="Address helper">ah</a></sup>
|
||||
</span>
|
||||
<span>
|
||||
<a href="https://files.arav.su">files</a>.<a href="http://qf5e43nlhvnrutmikuvbdfj3cmtthokpbaxtkm6mjlslttzvtgm4fxid.onion">onion</a>.<a href="http://[300:a98d:d6d0:8a08::e]">ygg</a>.<a href="http://files.arav.i2p">i2p</a><sup><a href="http://files.arav.i2p/?i2paddresshelper=48vtYgeVnju7B2FaR0zxUL3MQXN9QjK~Ggya45aANwm86mtpemuEkaskJmEQaFSd4FcDAFIiXHfNpfGqoupLwNmtgBmGRcuVV8xb2W~W6lM0oOhovjB37EUaMWs3AI5aIES84QOqApgwYX-ANIcwa~Kg6AbMuX8D8qnejuhBbuCffYah-TD8e~O0cnyqxzLTmxIGCyk2egdYXwanJyYFDocomIVfcqfJ0MgjIHhFQtkcb0e84bxvDzcAFIpEDrzAo4GVrFn-TCu0Lyf2ccqmVpucFl0UGhuVRxEt19KLd3PxlfwHv2lmzTZtq9CbnfaoPntUPx1sf84QnZDmrXWhVK8p3VvuPZMxjyz9KyhPjrGkO4E0oibDlvKuMsGEm-GkZsKxgXo~CrdcVtN8suAwW6rACAuk8gq2jUMBZBZ12migPZ7miHftEkOFHfgfUiKBwirrw~y9Zi261WX4-EVe2oD4pkhQOrqOKIoI-vv5z9CpQ7PKL531kgkipcBseXybBQAEAAcAAA==" title="Address helper">ah</a></sup>
|
||||
</span>
|
||||
<span>
|
||||
<a href="https://upload.arav.su">upload</a>.<a href="http://4usftbmjpfexkr2x5xbp5ukmygpmg4fgrnx2wbifsexqctooz5hmviyd.onion">onion</a>.<a href="http://[300:a98d:d6d0:8a08::e]">ygg</a>.<a href="http://upload.arav.i2p">i2p</a><sup><a href="http://upload.arav.i2p/?i2paddresshelper=b5NWA2vNydWSv6~8KN4e~td2UVGkYsayKPa1PnXI87A3gsg6m978tIehHLVN4XcCfUq4aB-59hqqZicorRnHKfV3lVdx9mdhC8Bhj~bMAcwMgWoXidqZNrWMoFGzWotFsa3nWh4zsRUSfrokecC8u9Y06byfSS1siyak0J6xpsggXRqqgNF0-8ncPeqvzBxHB9NRDXWEVJGS9HSpydWl1UpjgZffcd~NZroxkSAfughHcFAn2OLKkaZRe6WqCJQfJoXTCyz4wkFmYbH1CSddWlddmWaaU7icsbQrZm3XEqKTVKvm86G6ehxmzyHqCumc4GOWswcP0E51UQVOv-WA8R6SWQAj6ZnZhnCoCNFFEfW2lBiDmTnLJbfm-C-AdI6G1~dQ1~3FCH6wXWy-2DebpyoVVt9epzU7l4l2MVeaOUahbf6wcol1UbxPoR0XlGCXDe9700TYePjtpOU9vNkk2B1dQiZ1usgwseYuO26cRogSvbi8poz4BlCNO733HR1XBQAEAAcAAA==" title="Address helper">ah</a></sup>
|
||||
</span>
|
||||
<span>
|
||||
<a href="https://git.arav.su">git</a>.<a href="http://qqitm7qlsbbubwmjos4cqzmvkqidg34rfnbyhuydhalep33fbvh22xyd.onion">onion</a>.<a href="http://[300:a98d:d6d0:8a08::e]">ygg</a>.<a href="http://git.arav.i2p">i2p</a><sup><a href="http://git.arav.i2p/?i2paddresshelper=eFIfcBUv3lHFSnglHfncs5XXtYwm9gCpmAYuio~9CeENBAXKRggPiY1tQC-otCon2hCSpr56WlVBeZk1txKuUnbjHTN7GBFaKW5wJEO2WmKEWPKdcjUDOYZN0D3TwXaYfiBuELD3200lBfDmPEJ01iC2o7B5yvpOqtEKDcaqkIp4vafDuPPumJ~XiCGdUAe~vr52w3Tbuz5x7wbltk-gUELY0-ZAQBos4jOJ6QT1W1lhycHPhAK8qslgwfk94opyIl2pkRyuJhU-2VHc6Fsd621VXC86YAMT1SIfTZlFpoGVCFXDM~BXaLvygFaKf62qardAe0T48Ax6GxosAKXe-yLCVRaiD3KErULfwZXl23kQzRfxM4odG4DWeXawtuvypOmTjHT1skQHU0h52ujye5nT~2bOy14HkCoCnxJ7gSj3MjkmWLd1JhBsPH4ymRmI7jFJR1GYl8Wp5IigMBBzWfJUEEjS7QDHaRo5TCZJ9SXz6sgkGdfh74~r8FWL559gBQAEAAcAAA==" title="Address helper">ah</a></sup>
|
||||
</span>
|
||||
</section>
|
||||
<section>
|
||||
<p>
|
||||
Welcome, Anon. I'm Alexander aka Arav, I self-host some services for myself, friends and you. Not much I have to offer, but maybe you'll find something useful for yourself. :)
|
||||
</p>
|
||||
</section>
|
||||
}
|
||||
}
|
||||
|
||||
templ indexHead() {
|
||||
<link rel="stylesheet" href="assets/css/index.css"/>
|
||||
}
|
||||
|
56
web/mindflow.templ
Normal file
56
web/mindflow.templ
Normal file
@ -0,0 +1,56 @@
|
||||
package web
|
||||
|
||||
import "net/http"
|
||||
import "strings"
|
||||
import "time"
|
||||
|
||||
import "git.arav.su/Arav/dwelling-home/pkg/mindflow"
|
||||
import "git.arav.su/Arav/dwelling-home/pkg/util"
|
||||
|
||||
templ Mindflow(posts []mindflow.Post, categories []mindflow.Category, r *http.Request) {
|
||||
@base("Mindflow", "Updates on my infrastructure, my very important opinions and thoughts.", "updates, thoughts, opinions, blog, diary", "/mindflow", "Mindflow", mindflowHead()) {
|
||||
<p class="center">Here I post updates on websites and infrastructure, my very important opinions and thoughts no one asked for. If you'd like to subscribe to this bullshittery then <a href="/rss.xml">RSS feed</a> at your service. :)</p>
|
||||
<section id="filter" class="hidden">
|
||||
<p class="center">
|
||||
<button name="all">All</button>
|
||||
for _, category := range categories {
|
||||
<button name={ strings.ToLower(category.Name) }>{ category.Name }</button>
|
||||
}
|
||||
</p>
|
||||
</section>
|
||||
<section>
|
||||
for _, post := range posts {
|
||||
<article id={ post.PostID() }>
|
||||
<header>
|
||||
<a href={ templ.SafeURL("#" + post.PostID()) }>
|
||||
<h3>{ post.Category.Name }: { post.Title }</h3>
|
||||
</a>
|
||||
</header>
|
||||
for _, line := range strings.Split(post.Body, "\n") {
|
||||
if len(line) > 0 && line[0] == '>' {
|
||||
<p class="quote">{ line }</p>
|
||||
} else {
|
||||
<p>{ line }</p>
|
||||
}
|
||||
}
|
||||
<footer>
|
||||
if post.URL != "" {
|
||||
<a href={ templ.SafeURL(post.PostURL(r.Host, false)) }>{ post.PostURL(r.Host, false) }</a>
|
||||
} else {
|
||||
<span></span>
|
||||
}
|
||||
<time datetime={ util.ToClientTimezone(post.Date, r).Format(time.RFC1123) }>{ util.ToClientTimezone(post.Date, r).Format(time.RFC1123) }</time>
|
||||
</footer>
|
||||
</article>
|
||||
}
|
||||
if len(posts) == 0 {
|
||||
<p class="center">Nothing? There must be some... Looks like database went down.</p>
|
||||
}
|
||||
</section>
|
||||
}
|
||||
}
|
||||
|
||||
templ mindflowHead() {
|
||||
<link rel="stylesheet" href="/assets/css/mindflow.css"/>
|
||||
<script src="/assets/js/mindflow.js" defer></script>
|
||||
}
|
9
web/mindflow_admin.templ
Normal file
9
web/mindflow_admin.templ
Normal file
@ -0,0 +1,9 @@
|
||||
package web
|
||||
|
||||
import "net/http"
|
||||
|
||||
import "git.arav.su/Arav/dwelling-home/pkg/mindflow"
|
||||
|
||||
templ MindflowAdmin(posts []mindflow.Post, categories []mindflow.Category, r *http.Request) {
|
||||
@base("Mindflow Administration", "", "", "/mindflow/admin", "Mindflow Administration", nil)
|
||||
}
|
29
web/privacy.templ
Normal file
29
web/privacy.templ
Normal file
@ -0,0 +1,29 @@
|
||||
package web
|
||||
|
||||
import "net/http"
|
||||
|
||||
import "git.arav.su/Arav/dwelling-home/pkg/util"
|
||||
|
||||
templ Privacy(r *http.Request) {
|
||||
@base("Privacy", "Privacy statements for all of my services.", "privacy statements", "/privacy", "Privacy", nil) {
|
||||
<section id="privacy">
|
||||
<h2>Privacy statements</h2>
|
||||
<h3>General data</h3>
|
||||
<p>Across all of my Web-services following data is being collected: date of access, IP-address, User-Agent, referer URL, request URL.</p>
|
||||
<h3>Use of JavaScript</h3>
|
||||
<p>JS is used on a <a href="/">main website</a> at a guestbook page to refresh CAPTCHA; at mindflow page to filter posts by categories.</p>
|
||||
<p><a href={ templ.URL(util.GetServiceByHost(r.Host, util.ServiceRadio)) }>Radio service</a> uses JS to update Last N songs list section, and to get current radio statistics.</p>
|
||||
<p><a href={ templ.URL(util.GetServiceByHost(r.Host, util.ServiceFiles)) }>Files service</a> uses JS to add functionality such as an overlay to view files without the need to leave a site, and implements some keyboard control for convenience.</p>
|
||||
<h3>Upload service specific</h3>
|
||||
<p>Every action (upload, download, and delete) is being logged and includes this additional data:</p>
|
||||
<ol>
|
||||
<li>File's name it was uploaded/downloaded with;</li>
|
||||
<li>Unsalted SHA-256 hash of a file;</li>
|
||||
<li>A salted hash encoded as base64 in raw URL variant that is used to download/delete a file;</li>
|
||||
<li>File's size.</li>
|
||||
</ol>
|
||||
<p>And I will cooperate with law enforcements and provide them with all information (logs and a file itself if it is still present).</p>
|
||||
<p>As already stated at <a href={ templ.URL(util.GetServiceByHost(r.Host, util.ServiceUpload)) }>Upload service</a>'s page, file's content must comply with law of Russian Federation. Anything like extremist materials, CP, and so on is forbidden.</p>
|
||||
</section>
|
||||
}
|
||||
}
|
@ -1,38 +1,37 @@
|
||||
package web
|
||||
|
||||
import "time"
|
||||
import "strings"
|
||||
import "net/http"
|
||||
import "strings"
|
||||
import "time"
|
||||
|
||||
import "git.arav.su/Arav/dwelling-home/pkg/mindflow"
|
||||
import "git.arav.su/Arav/dwelling-home/pkg/util"
|
||||
|
||||
templ RSS(host, author string, posts []mindflow.Post, r *http.Request) {
|
||||
@templ.Raw("<?xml version=\"1.0\" encoding=\"utf-8\" ?>")
|
||||
<rss version="2.0">
|
||||
<channel>
|
||||
<title>Arav's dwelling</title>
|
||||
<description>What's going on with me and my machines.</description>
|
||||
<language>en-gb</language>
|
||||
<link>{ host }</link>
|
||||
|
||||
for _, post := range posts {
|
||||
<item>
|
||||
<title>{ post.Title }</title>
|
||||
<category>{ post.Category.Name }</category>
|
||||
<guid>{ post.PostID() }</guid>
|
||||
<pubDate>{ util.ToClientTimezone(post.Date, r).Format(time.RFC1123Z) }</pubDate>
|
||||
<link>{ post.PostURL(r.Host, true) }</link>
|
||||
<author>{ author }</author>
|
||||
<description>
|
||||
@templ.Raw("<![CDATA[")
|
||||
for _, line := range strings.Split(post.Body, "\n") {
|
||||
<p>{ line }</p>
|
||||
}
|
||||
@templ.Raw("]]>")
|
||||
</description>
|
||||
</item>
|
||||
}
|
||||
</channel>
|
||||
</rss>
|
||||
}
|
||||
@templ.Raw("<?xml version=\"1.0\" encoding=\"utf-8\" ?>")
|
||||
<rss version="2.0">
|
||||
<channel>
|
||||
<title>Arav's dwelling</title>
|
||||
<description>What's going on with me and my machines.</description>
|
||||
<language>en-gb</language>
|
||||
<link>{ host }</link>
|
||||
for _, post := range posts {
|
||||
<item>
|
||||
<title>{ post.Title }</title>
|
||||
<category>{ post.Category.Name }</category>
|
||||
<guid>{ post.PostID() }</guid>
|
||||
<pubDate>{ util.ToClientTimezone(post.Date, r).Format(time.RFC1123Z) }</pubDate>
|
||||
<link>{ post.PostURL(r.Host, true) }</link>
|
||||
<author>{ author }</author>
|
||||
<description>
|
||||
@templ.Raw("<![CDATA[")
|
||||
for _, line := range strings.Split(post.Body, "\n") {
|
||||
<p>{ line }</p>
|
||||
}
|
||||
@templ.Raw("]]>")
|
||||
</description>
|
||||
</item>
|
||||
}
|
||||
</channel>
|
||||
</rss>
|
||||
}
|
||||
|
172
web/stuff.templ
Normal file
172
web/stuff.templ
Normal file
@ -0,0 +1,172 @@
|
||||
package web
|
||||
|
||||
import "net/http"
|
||||
|
||||
import "git.arav.su/Arav/dwelling-home/pkg/util"
|
||||
|
||||
templ Stuff(r *http.Request) {
|
||||
{{ gitSite := util.GetServiceByHost(r.Host, util.ServiceGit) }}
|
||||
|
||||
@base("Stuff", "Here I share my programs, scripts, articles, may be other stuff.", "articles, programs, personal projects, own music", "/stuff", "Stuff", nil) {
|
||||
<p class="center">Here lies everything I've made that I'm willing to share.</p>
|
||||
<section id="articles">
|
||||
<h2>Articles</h2>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Last Update</th>
|
||||
<th>Article</th>
|
||||
</tr>
|
||||
for _, entry := range Metadata {
|
||||
<tr>
|
||||
<td>
|
||||
<time datetime={ entry.Date.Format("2006-01-02") }>{ entry.Date.Format("02 January 2006") }</time>
|
||||
</td>
|
||||
<td>
|
||||
<a href={ templ.URL(entry.URL) }>{ entry.Title }</a>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</table>
|
||||
</section>
|
||||
<section id="programs-scripts">
|
||||
<h2>Programs and scripts</h2>
|
||||
<table>
|
||||
<tr>
|
||||
<td><b>mccl</b></td>
|
||||
<td>0.1.2 (14 December 2023)</td>
|
||||
<td>Go</td>
|
||||
<td>GPLv3</td>
|
||||
<td>
|
||||
<a href={ templ.URL(gitSite + "/Arav/mccl") }>source</a>
|
||||
<a href={ templ.URL(gitSite + "/Arav/mccl/releases") }>releases</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="5">
|
||||
<p>A console Minecraft launcher. Take a look at README.md for explanation.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>httpr</b></td>
|
||||
<td>0.3.2 (20 September 2023)</td>
|
||||
<td>Go</td>
|
||||
<td>MIT</td>
|
||||
<td>
|
||||
<a href={ templ.URL(gitSite + "/Arav/httpr") }>source</a>
|
||||
<a href={ templ.URL(gitSite + "/Arav/httpr/releases") }>releases</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="5">
|
||||
<p>A simple HTTP router that supports having both regular and parametrised path's parts at the same level, like <code>/assets/*filepath</code> and <code>/:a/:b</code> with the same HTTP method.</p>
|
||||
<p>Yeah, not as efficient as httprouter is, but in my case no performance loose was noticed (on a small amount of paths). Yet I gained prettiness because it allowed me, for example, to ditch <code>/f/</code> part and leave just <code>/:hash/:name</code> instead of <code>/f/:hash/:name</code> in a dwelling-upload service.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>justguestbook</b></td>
|
||||
<td>1.3.2 (22 May 2023)</td>
|
||||
<td>Go</td>
|
||||
<td>MIT</td>
|
||||
<td>
|
||||
<a href={ templ.URL(gitSite + "/Arav/justguestbook") }>source</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="5">
|
||||
<p>A simple guestbook with owner's replies implementation made into a library.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>justcaptcha</b></td>
|
||||
<td>2.1.0 (12 August 2023)</td>
|
||||
<td>Go</td>
|
||||
<td>MIT</td>
|
||||
<td>
|
||||
<a href={ templ.URL(gitSite + "/Arav/justcaptcha") }>source</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="5">
|
||||
<p>A simple CAPTCHA implementation.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>kwh-cost</b></td>
|
||||
<td>1.1.3 (21 May 2024)</td>
|
||||
<td>C</td>
|
||||
<td>MIT+NIGGER</td>
|
||||
<td>
|
||||
<a href={ templ.URL(gitSite + "/Arav/kwh-cost") }>source</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="5">
|
||||
<p>KWh cost calculator in C.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>httpprocprobed</b></td>
|
||||
<td>3.1.1 (13 January 2024)</td>
|
||||
<td>Go</td>
|
||||
<td>MIT+NIGGER</td>
|
||||
<td>
|
||||
<a href={ templ.URL(gitSite + "/Arav/httpprocprobed") }>source</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="5">
|
||||
<p>It returns a list of processes and if they are running in a JSON format via HTTP GET request on <code>/processes</code> endpoint. Under the hood it searches in a /proc/ directory. It is being used on about page to show wether service's running or not.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>ScrapTheChan</b></td>
|
||||
<td>0.5.0 (3 May 2021)</td>
|
||||
<td>Python</td>
|
||||
<td>MIT</td>
|
||||
<td>
|
||||
<a href={ templ.URL(gitSite + "/Arav/ScrapTheChan") }>source</a>
|
||||
<a href={ templ.URL(gitSite + "/Arav/ScrapTheChan/releases") }>releases</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="5">
|
||||
<p>Imageboards file scraper using theirs JSON API. Currently supported: 4chan.org, lainchan.org, 2ch.hk and 8kun.top.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>OpenNIC active domains extraction script</b></td>
|
||||
<td>10 July 2020</td>
|
||||
<td>Bash</td>
|
||||
<td>MIT</td>
|
||||
<td>
|
||||
<a href={ templ.URL(gitSite + "/Arav/opennic-extract-domains") }>source</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="5">
|
||||
<p>Bash script for BIND9 that extracts domains from zone files of OpenNIC and forms a list of domains that have an IP-address.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>PiggyBank</b></td>
|
||||
<td>1.0.0 (8 July 2020)</td>
|
||||
<td>Python</td>
|
||||
<td>MIT</td>
|
||||
<td>
|
||||
<a href={ templ.URL(gitSite + "/Arav/PiggyBank") }>source</a>
|
||||
<a href={ templ.URL(gitSite + "/Arav/PiggyBank/releases") }>releases</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="5">
|
||||
<p>A program to help you to keep track of your piggy bank. A simple script I once wrote that I rewrote and made into a package just to learn how to do it.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</section>
|
||||
<section id="music">
|
||||
<h2>Music</h2>
|
||||
<p>There was a period in my life when I was playing with audio sequencers. I lost all project files and only 3 tracks survived in mp3 and they <a href={ templ.URL(util.GetServiceByHost(r.Host, util.ServiceFiles) + "/music/My%20tracks,%20that%20survived/") }>can be found here</a>.</p>
|
||||
</section>
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user