initial commit
This commit is contained in:
commit
c21f569144
37 changed files with 3956 additions and 0 deletions
256
views/template.templ
Normal file
256
views/template.templ
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
package views
|
||||
|
||||
import (
|
||||
"foobar/database"
|
||||
"foobar/model"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
templ indexLayout() {
|
||||
<!DOCTYPE html>
|
||||
<html lang="pt-BR">
|
||||
<head>
|
||||
<title>Mude meu título!</title>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<meta name="htmx-config" content='{ "responseHandling":[{"code":"422", "swap": true}, {"code":"200", "swap": true}] }' />
|
||||
<!-- tailwind -->
|
||||
<link href="/static/css/output.css" rel="stylesheet"/>
|
||||
<!-- markdown styling -->
|
||||
<link href="/static/css/github-markdown.css" rel="stylesheet"/>
|
||||
<!-- daisyUI -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/daisyui@5" rel="stylesheet" type="text/css" />
|
||||
<!-- daisyUI Themes -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/daisyui@5/themes.css" rel="stylesheet" type="text/css" />
|
||||
// <script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
|
||||
<!-- HTMX -->
|
||||
<script src="https://unpkg.com/htmx.org@2.0.4"></script>
|
||||
<!-- Hyperscript -->
|
||||
<script src="https://unpkg.com/hyperscript.org@0.9.14"></script>
|
||||
<style>
|
||||
html, body {
|
||||
min-height: 100vh;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="flex-wrap flex content-center justify-between flex-col bg-base-100 text-sm"
|
||||
hx-boost="true" hx-push-url="true" hx-target="this">
|
||||
{ children... }
|
||||
<footer></footer>
|
||||
</body>
|
||||
</html>
|
||||
}
|
||||
|
||||
templ mainCenterBody() {
|
||||
@indexLayout() {
|
||||
<main class="w-full" >
|
||||
{ children... }
|
||||
</main>
|
||||
}
|
||||
}
|
||||
|
||||
const toggleButtonInMeUntilLoad =
|
||||
`on every htmx:beforeSend
|
||||
tell <button/> in me
|
||||
toggle [@disabled='true'] until htmx:afterOnLoad
|
||||
end
|
||||
end`
|
||||
|
||||
func safeURL(s string) string {
|
||||
return fmt.Sprint(templ.SafeURL(s))
|
||||
}
|
||||
|
||||
templ Index() {
|
||||
@mainCenterBody() {
|
||||
<div class="hero-content">
|
||||
<div class="max-w-md text-center">
|
||||
<h1>hakobox</h1>
|
||||
<p>nothing here...</p>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
templ boxUploadSidebar(boxURL model.BoxURL) {
|
||||
@mainCenterBody() {
|
||||
<div class="">
|
||||
<section class="static md:fixed top-0 left-0 z-10 w-full md:w-3/9 p-10 bg-base-200 h-full ">
|
||||
<header>
|
||||
<h1>hakobox</h1>
|
||||
<p>It's temporary file sharing but everyone gets to contribute! </p>
|
||||
<p class="leading-tight font-medium text-black">Drop in a file to be added to this box </p>
|
||||
</header>
|
||||
<form id="add-file"
|
||||
hx-trigger="submit"
|
||||
hx-post={safeURL(fmt.Sprintf("/box/%s", boxURL))}
|
||||
hx-encoding="multipart/form-data">
|
||||
<fieldset class="fieldset">
|
||||
<legend class="fieldset-legend">Pick a file</legend>
|
||||
<input name="file" type="file" class="file-input" style="width: 100%;" multiple required/>
|
||||
<label class="fieldset-label">Max size 2MB</label>
|
||||
</fieldset>
|
||||
<fieldset class="fieldset">
|
||||
<legend class="fieldset-legend">Edit code</legend>
|
||||
<input type="text" class="input" name="edit_code" placeholder="Type here" style="width: 100%;"/>
|
||||
<p class="label">Optional</p>
|
||||
</fieldset>
|
||||
@errorTarget()
|
||||
<button type="submit" class="btn btn-primary mb-5">Add to the box!</button>
|
||||
<div class="text-center">
|
||||
<a class="link link-primary block mb-0"
|
||||
href={templ.SafeURL(fmt.Sprintf("/box/%s/inside", boxURL))}>
|
||||
See what's inside
|
||||
</a>
|
||||
<a class="link link-primary block mb-0"
|
||||
href={templ.SafeURL(fmt.Sprintf("/box/%s", boxURL))}>
|
||||
Front page
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
<section class="md:px-20 p-4 md:my-40 m-0 md:ml-auto md:max-w-6/9">
|
||||
{ children... }
|
||||
</section>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
templ BoxUpload(box model.Box) {
|
||||
@boxUploadSidebar(box.Url()) {
|
||||
<div class="markdown-body">
|
||||
@templ.Raw(box.Header())
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
templ NewBox(boxURL model.BoxURL, templateReadme model.Markdown) {
|
||||
@boxUploadSidebar(boxURL) {
|
||||
<div class="markdown-body">
|
||||
@templ.Raw(templateReadme)
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
templ Box(boxURL model.BoxURL, files []model.File) {
|
||||
@boxUploadSidebar(boxURL) {
|
||||
<main class="inline-flex flex-wrap gap-0 md:gap-5 mt-20 w-full h-full justify-start md:justify-center">
|
||||
if len(files) == 0 {
|
||||
<h2 class="m-auto">Empty box.</h2>
|
||||
} else {
|
||||
for i := range files {
|
||||
@fileCard(files[i])
|
||||
}
|
||||
}
|
||||
</main>
|
||||
}
|
||||
}
|
||||
|
||||
func fileDisplay(file model.File) templ.Component {
|
||||
switch {
|
||||
case file.Mime().IsImage():
|
||||
return fileImageFigure(file)
|
||||
case file.Mime().IsVideo():
|
||||
return fileVideoFigure(file)
|
||||
default:
|
||||
return unknownFileFigure()
|
||||
// panic(fmt.Errorf("unrecognized mime: %s", file.Mime))
|
||||
}
|
||||
}
|
||||
|
||||
templ fileCard(file model.File) {
|
||||
<a class="card w-1/2 md:w-2xs aspect-square mb-10" href={templ.SafeURL(fmt.Sprintf("/static/box/%s", file.ID()))} target="_blank">
|
||||
<figure class="flex flex-col p-1 m-auto mb-auto md:mb-0 text-center">
|
||||
@fileDisplay(file)
|
||||
</figure>
|
||||
<div class="hidden md:inline font-light text-sm" style="text-wrap: nowrap;">
|
||||
<p title={file.Name()}>{shorten(file.Name())}</p>
|
||||
<p title={file.Name()}>{file.CreatedAt().Format(time.DateOnly)}</p>
|
||||
<p>{formatSize(file.Size())} {file.Mime().PrettyType()}</p>
|
||||
</div>
|
||||
</a>
|
||||
}
|
||||
|
||||
templ fileImageFigure(file model.File) {
|
||||
<img
|
||||
title={file.Name()}
|
||||
loading="lazy"
|
||||
src={fmt.Sprintf("/static/box/%s", file.ID())}
|
||||
alt={file.Name()} />
|
||||
}
|
||||
|
||||
templ fileVideoFigure(file model.File) {
|
||||
<video title={file.Name()} loading="lazy" alt={file.Name()} >
|
||||
<source src={fmt.Sprintf("/static/box/%s", file.ID())}/>
|
||||
</video>
|
||||
}
|
||||
|
||||
|
||||
templ unknownFileFigure() {
|
||||
<div>unknown format!</div>
|
||||
}
|
||||
|
||||
|
||||
func shorten(text string) string {
|
||||
if len(text) > 41 {
|
||||
return fmt.Sprintf("%s...", text[:41-3])
|
||||
} else {
|
||||
return text
|
||||
}
|
||||
}
|
||||
|
||||
func formatSize(size int64) string {
|
||||
units := []string{"b", "Kb", "Mb", "Gb"}
|
||||
i := 0
|
||||
fSize := float64(size)
|
||||
for fSize >= 1000 && i < len(units)-1 {
|
||||
fSize /= 1000
|
||||
i++
|
||||
}
|
||||
return fmt.Sprintf("%.2f %s", fSize, units[i])
|
||||
}
|
||||
|
||||
templ FourOfour() {
|
||||
@indexLayout() {
|
||||
<div>404</div>
|
||||
}
|
||||
}
|
||||
|
||||
templ Logged(usuario *database.Usuario) {
|
||||
@indexLayout() {
|
||||
<p>Logado como: { usuario.Nome }</p>
|
||||
<div style="text-align: center;">
|
||||
<p>
|
||||
<a href="/">index</a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="/logout">logout</a>
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
templ errorTarget() {
|
||||
<div id="error-target">
|
||||
</div>
|
||||
}
|
||||
|
||||
templ ErrorBox(msg string) {
|
||||
<div role="alert" class="bounce mt-3 relative flex flex-col w-full p-3 text-sm text-white bg-red-600 rounded-md">
|
||||
<p class="flex text-base">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="h-5 w-5 mr-2 mt-0.5"><path stroke-linecap="round" stroke-linejoin="round" d="M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z"></path></svg>
|
||||
Error
|
||||
</p>
|
||||
<p class="ml-4 p-3">
|
||||
{ msg }
|
||||
</p>
|
||||
|
||||
<button class="flex items-center justify-center transition-all w-8 h-8 rounded-md text-white hover:bg-white/10 active:bg-white/10 absolute top-1.5 right-1.5" type="button"
|
||||
_='on click tell closest <div[role="alert"]/> transition opacity to 0 then remove yourself end'
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" class="h-5 w-5" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"></path></svg>
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue