256 lines
7.1 KiB
Text
256 lines
7.1 KiB
Text
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>
|
|
}
|