more polish, add picocss, add more js and web features

This commit is contained in:
Adora Laura Kalb 2023-05-04 17:16:56 +02:00
parent a5b6232c77
commit ce47b12e09
Signed by: adoralaura
GPG key ID: 7A4552166FC8C056
25 changed files with 593 additions and 1862 deletions

View file

@ -0,0 +1,9 @@
services:
db:
image: postgres
restart: always
environment:
POSTGRES_PASSWORD: example
POSTGRES_USER: go-urlsh
POSTGRES_DB: go-urlsh

View file

@ -58,6 +58,7 @@ func SetupFiber() error {
fiberapp.Get("/admin/", web.HandleAdminLinkIndexGet) fiberapp.Get("/admin/", web.HandleAdminLinkIndexGet)
fiberapp.Get("/admin/links/new", web.HandleAdminLinkNewGet) fiberapp.Get("/admin/links/new", web.HandleAdminLinkNewGet)
fiberapp.Get("/admin/links/edit/:id", web.HandleAdminLinkEditGet)
fiberapp.Static("/admin/", "./web") fiberapp.Static("/admin/", "./web")

View file

@ -1,22 +1,62 @@
package web package web
import ( import (
"codeberg.org/lauralani/go-urlsh/internal/db"
"codeberg.org/lauralani/go-urlsh/internal/misc"
"codeberg.org/lauralani/go-urlsh/models" "codeberg.org/lauralani/go-urlsh/models"
"context" "context"
"database/sql"
"fmt" "fmt"
"github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2"
"log"
) )
func HandleAdminLinkNewGet(c *fiber.Ctx) error { func HandleAdminLinkNewGet(c *fiber.Ctx) error {
return c.Render("add_link", nil) return c.Render("add_link", nil)
} }
func HandleAdminLinkIndexGet(c *fiber.Ctx) error { func HandleAdminLinkEditGet(c *fiber.Ctx) error {
var links []models.Link if !db.IsCookieValid(c.Cookies(misc.CookieName, "")) {
c.Location("/admin/")
err := models.DB.NewSelect().Model(&links).Scan(context.Background()) c.Status(fiber.StatusSeeOther)
if err != nil { return nil
return fmt.Errorf("error querying links: %v", err.Error()) }
var link = new(models.Link)
var id = c.Params("id", "")
if id == "" {
log.Println("[HandleAdminLinkEditGet] no id param given")
return fiber.NewError(fiber.StatusBadRequest, "400 Bad Request")
}
err := models.DB.NewSelect().Model(link).Where("id = ?", id).Scan(context.Background())
if err != nil {
if err == sql.ErrNoRows {
log.Printf("[HandleAdminLinkEditGet] Shortlink %v not found\n", id)
return fiber.NewError(fiber.StatusNotFound, "404 Not Found")
} else {
log.Printf("[HandleAdminLinkEditGet] Error querying Shortlink %v from database: %v\n", id, err)
return fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error")
}
}
return c.Render("edit_link", link)
}
func HandleAdminLinkIndexGet(c *fiber.Ctx) error {
if !db.IsCookieValid(c.Cookies(misc.CookieName, "")) {
c.Location("/admin/login")
c.Status(fiber.StatusSeeOther)
return nil
} else {
var links []models.Link
err := models.DB.NewSelect().Model(&links).Scan(context.Background())
if err != nil {
return fmt.Errorf("error querying links: %v", err.Error())
}
return c.Render("links", links)
} }
return c.Render("links", links)
} }

View file

@ -1,6 +1,7 @@
package web package web
import ( import (
"codeberg.org/lauralani/go-urlsh/internal/db"
"codeberg.org/lauralani/go-urlsh/internal/misc" "codeberg.org/lauralani/go-urlsh/internal/misc"
"codeberg.org/lauralani/go-urlsh/models" "codeberg.org/lauralani/go-urlsh/models"
"context" "context"
@ -31,8 +32,14 @@ func HandleAdminLoginPost(c *fiber.Ctx) error {
if passwordsum == user.PasswordHash { if passwordsum == user.PasswordHash {
// Passwords match // Passwords match
var expires time.Time
if login.Remember == "on" {
expires = time.Now().Add(30 * 24 * time.Hour)
} else {
expires = time.Now().Add(24 * time.Hour)
}
expires := time.Now().Add(30 * 24 * time.Hour)
key := uuid.New().String() key := uuid.New().String()
dblogin := new(models.Login) dblogin := new(models.Login)
@ -68,5 +75,11 @@ func HandleAdminLoginPost(c *fiber.Ctx) error {
} }
func HandleAdminLoginGet(c *fiber.Ctx) error { func HandleAdminLoginGet(c *fiber.Ctx) error {
return c.Render("login", nil) if db.IsCookieValid(c.Cookies(misc.CookieName, "")) {
c.Location("/admin/")
c.Status(fiber.StatusSeeOther)
return nil
} else {
return c.Render("login", nil)
}
} }

View file

@ -15,4 +15,5 @@ type Login struct {
type LoginRequest struct { type LoginRequest struct {
Username string `json:"username"` Username string `json:"username"`
Password string `json:"password"` Password string `json:"password"`
Remember string `json:"remember"`
} }

View file

@ -1,53 +1,74 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset='utf-8'> <meta charset='utf-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'> <meta http-equiv='X-UA-Compatible' content='IE=edge'>
<title>Add new Shortlink - go-urlsh</title> <title>Add new Shortlink - go-urlsh</title>
<meta name='viewport' content='width=device-width, initial-scale=1'> <meta name='viewport' content='width=device-width, initial-scale=1'>
<link rel="stylesheet" href="/admin/style.css"> <link rel="stylesheet" href="/admin/pico.min.css">
<link rel="stylesheet" href="/admin/custom.css">
<script src="/admin/link_add.js" defer></script>
<script src="/admin/misc.js" defer></script>
</head> </head>
<body> <body>
<form action="javascript:void(0);" style="margin-top: 2em"> <nav class="container-fluid">
<fieldset id="form_fields"> <ul>
<legend>Add a new Shortlink</legend> <li>
<p>* shows a required field</p> <a href="/admin/" class="contrast"><strong>go-urlsh</strong></a>
<label for="linkname">Shortlink Name (leave empty for random)</label> </li>
<input type="text" name="linkname" id="linkname" placeholder="shortlink"> </ul>
<ul>
<li>
<a href="/admin/">Links</a>
</li>
<li>
<a href="/admin/apikeys/">API Keys</a>
</li>
<li>
<a href="javascript: void(0)" >Users (coming soon)</a>
</li>
<li>
<a href="javascript: Logout()" style="color: red;">Logout</a>
</li>
</ul>
</nav>
<main class="container" style="padding: 0">
<form action="javascript:HandleSubmit();" style="margin: 0">
<fieldset id="form_fields">
<hgroup>
<h1>Add new shortlink</h1>
<h2><i style="color: red;">*</i> marks required fields</h2>
</hgroup>
<label for="linkname">Shortlink Name (leave empty for random)</label>
<input type="text" name="linkname" id="linkname" placeholder="shortlink">
<label for="link">Link *</label> <label for="link">Link <i style="color: red;">*</i></label>
<input type="text" name="link" id="link" placeholder="https://" style="width: 97%" onchange="HandleChange()"> <input type="text" name="link" id="link" placeholder="https://" onchange="HandleChange()">
<label for="description">Description</label> <label for="description">Description</label>
<input type="text" name="description" id="description" placeholder="" style="width: 97%"> <input type="text" name="description" id="description" placeholder="">
<div> <div>
<input type="submit" id="submit" value="Add" onclick="HandleSubmit()" style="margin-top: 1em;"> <input type="submit" id="submit" value="Add" style="margin-top: 1em;">
</div> </div>
</fieldset> </fieldset>
<dialog id="dialog-info">
<h2 id="dialog-heading"></h2>
<p id="dialog-text"></p>
<form method="dialog">
<button>Close</button>
</form>
</dialog>
<dialog id="dialog-info">
<h2 id="dialog-heading"></h2>
<p id="dialog-text"></p>
<form method="dialog">
<button>Close</button>
</form> </form>
</dialog> </main>
{{template "partials/footer" .}}
</form>
<footer>
<p>go-urlsh - <a href="/">Home</a> -
<a href="https://codeberg.org/lauralani/go-urlsh" target="_blank">Source Code</a> -
<a href="https://codeberg.org/lauralani/go-urlsh/src/branch/main/LICENSE" target="_blank">License</a>
</p>
</footer>
<script src="/admin/link_add.js"></script>
</body> </body>
</html>
</html>

74
views/edit_link.tmpl Normal file
View file

@ -0,0 +1,74 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset='utf-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<title>Edit Shortlink - go-urlsh</title>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<link rel="stylesheet" href="/admin/pico.min.css">
<link rel="stylesheet" href="/admin/custom.css">
<script src="/admin/link_add.js" defer></script>
<script src="/admin/misc.js" defer></script>
</head>
<body>
<nav class="container-fluid">
<ul>
<li>
<a href="/admin/" class="contrast"><strong>go-urlsh</strong></a>
</li>
</ul>
<ul>
<li>
<a href="/admin/">Links</a>
</li>
<li>
<a href="/admin/apikeys/">API Keys</a>
</li>
<li>
<a href="javascript: void(0)" >Users (coming soon)</a>
</li>
<li>
<a href="javascript: Logout()" style="color: red;">Logout</a>
</li>
</ul>
</nav>
<main class="container" style="padding: 0">
<form action="javascript:HandleSubmit();" style="margin: 0">
<fieldset id="form_fields">
<hgroup>
<h1>Edit shortlink</h1>
<h2><i style="color: red;">*</i> marks required fields</h2>
</hgroup>
<label for="linkname">Shortlink Name (to change this, delete the shortlink and add it again)</label>
<input type="text" name="linkname" id="linkname" value="{{.ID}}" data-tooltip="" readonly>
<label for="link">Link <i style="color: red;">*</i></label>
<input type="text" name="link" id="link" value="{{.URL}}">
<label for="description">Description</label>
<input type="text" name="description" id="description" value="{{.Description}}">
<div>
<input type="submit" id="submit" value="Save" style="margin-top: 1em;">
</div>
</fieldset>
<dialog id="dialog-info">
<h2 id="dialog-heading"></h2>
<p id="dialog-text"></p>
<form method="dialog">
<button>Close</button>
</form>
</dialog>
</form>
</main>
{{template "partials/footer" .}}
</body>
</html>

View file

@ -1,57 +1,77 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset='utf-8'> <meta charset='utf-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'> <meta http-equiv='X-UA-Compatible' content='IE=edge'>
<title>Shortlinks - go-urlsh</title> <title>Shortlinks - go-urlsh</title>
<meta name='viewport' content='width=device-width, initial-scale=1'> <meta name='viewport' content='width=device-width, initial-scale=1'>
<link rel="stylesheet" href="/admin/style.css"> <link rel="stylesheet" href="/admin/pico.min.css">
<link rel="stylesheet" href="/admin/custom.css">
<script src="/admin/links.js" defer></script>
<script src="/admin/misc.js" defer></script>
<style> <style>
td { vertical-align: middle; } td {
vertical-align: middle;
text-align: left;
}
</style> </style>
</head> </head>
<body> <body>
<nav class="container-fluid">
<a href="/admin/links/new"><button type="button" id="add-new-button">Add new Shortlink</button></a> <ul>
<li>
<table> <a href="/admin/" class="contrast"><strong>go-urlsh</strong></a>
<thead> </li>
<tr> </ul>
<th>Shortlink</th> <ul>
<th>URL</th> <li>
<th> </th> <a href="/admin/links/new" style="color: greenyellow;">Add new Shortlink</a>
<th> </th> </li>
</tr> <li>
</thead> <a href="/admin/apikeys/">API Keys</a>
<tbody> </li>
{{range .}} <li>
<tr> <a href="javascript: void(0)" >Users (coming soon)</a>
<td><a href="#" onclick="HandleCopy('{{.ID}}')">{{.ID}}</a></td> </li>
<td><a href="{{.URL}}" target="_blank">{{.URL}}</a></td> <li>
<td style="text-align: right;"> <a href="javascript: Logout()" style="color: red;">Logout</a>
<button type="button" id="edit-button" onclick="HandleEdit('{{.ID}}')"> </li>
Edit </ul>
</button> </nav>
</td> <main class="container">
<td style="text-align: right;"> <table class="n-table">
<button type="button" id="delete-button" onclick="HandleDelete('{{.ID}}')"> <thead>
Delete <tr>
</button> <th>Shortlink</th>
</td> <th>URL</th>
</tr> <th> </th>
{{end}} <th> </th>
</tbody> </tr>
</table> </thead>
<tbody>
{{range .}}
<footer> <tr>
<p>go-urlsh - <a href="/admin/">Home</a> - <td><a href="javascript: HandleCopy('{{.ID}}');" data-tooltip="click to copy">{{.ID}}</a></td>
<a href="https://codeberg.org/lauralani/go-urlsh" target="_blank">Source Code</a> - <td><a href="{{.URL}}" target="_blank" {{if .Description}}data-tooltip="{{.Description}}"{{end}}>{{.URL}}</a></td>
<a href="https://codeberg.org/lauralani/go-urlsh/src/branch/main/LICENSE" target="_blank">License</a> <td style="text-align: right;">
</p> <a href="/admin/links/edit/{{.ID}}">
</footer> Edit
</a>
<script src="/admin/links.js"></script> </td>
<td style="text-align: right;">
<a href="javascript: HandleDelete('{{.ID}}');">
Delete
</a>
</td>
</tr>
{{end}}
</tbody>
</table>
</main>
{{template "partials/footer" .}}
</body> </body>
</html>
</html>

View file

@ -1,22 +1,43 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset='utf-8'> <meta charset='utf-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'> <meta http-equiv='X-UA-Compatible' content='IE=edge'>
<title>Page Title</title> <title>Login - go-urlsh</title>
<meta name='viewport' content='width=device-width, initial-scale=1'> <meta name='viewport' content='width=device-width, initial-scale=1'>
<link rel="stylesheet" href="/admin/style.css"> <link rel="stylesheet" href="/admin/pico.min.css">
<style>
</style>
</head> </head>
<body> <body>
<h3 id="form-elements">Form elements</h3> <main class="container">
<form method="post" action="/admin/login"> <article class="grid">
<label for="username">Username</label> <div>
<input type="text" name="username" id="username" placeholder="username"> <hgroup>
<h1 style='--color: var(--h1-color); font-weight: var(--font-weight); font-size: var(--font-size); font-family: var(--font-family);'>Sign in</h1>
</hgroup>
<form method="post" action="/admin/login" style="margin-bottom: 0;" autocomplete="off">
<label for="username">Username</label>
<input type="text" name="username" id="username" placeholder="Username">
<label for="password">Password</label> <label for="password">Password</label>
<input type="hidden" name="password" id="password" placeholder="password"> <input type="password" name="password" id="password" placeholder="*******">
<input type="submit" value="Login"> <fieldset>
</form> <label for="remember">
<input type="checkbox" role="switch" id="remember" name="remember" />
Stay logged in
</label>
</fieldset>
<input type="submit" value="Login" class="contrast">
</form>
</div>
</article>
</main>
</body> </body>
</html>
</html>

View file

@ -0,0 +1,8 @@
<footer class="container-fluid">
<small>
&#169; 2023 Laura Kalb -
<a href="https://codeberg.org/lauralani/go-urlsh" target="_blank" class="secondary">Source Code</a> -
<a href="https://picocss.com" target="_blank" class="secondary">Theme: PicoCSS</a> -
<a href="https://codeberg.org/lauralani/go-urlsh/src/branch/main/LICENSE" target="_blank" class="secondary">License</a>
</small>
</footer>

View file

@ -1,49 +1,74 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset='utf-8'> <meta charset='utf-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'> <meta http-equiv='X-UA-Compatible' content='IE=edge'>
<title>Add new Shortlink - go-urlsh</title> <title>Add new Shortlink - go-urlsh</title>
<meta name='viewport' content='width=device-width, initial-scale=1'> <meta name='viewport' content='width=device-width, initial-scale=1'>
<link rel="stylesheet" href="/admin/simple.min.css"> <link rel="stylesheet" href="/admin/pico.min.css">
<link rel="stylesheet" href="/admin/custom.css">
<script src="/admin/link_add.js" defer></script>
<script src="/admin/misc.js" defer></script>
</head> </head>
<body> <body>
<form action="javascript:void(0);" style="margin-top: 2em"> <nav class="container-fluid">
<fieldset id="form_fields"> <ul>
<legend>Add a new Shortlink</legend> <li>
<p>* shows a required field</p> <a href="/admin/" class="contrast"><strong>go-urlsh</strong></a>
<label for="linkname">Shortlink Name (leave empty for random)</label> </li>
<input type="text" name="linkname" id="linkname" placeholder="shortlink"> </ul>
<ul>
<li>
<a href="/admin/">Links</a>
</li>
<li>
<a href="/admin/apikeys/">API Keys</a>
</li>
<li>
<a href="javascript: void(0)" >Users (coming soon)</a>
</li>
<li>
<a href="javascript: Logout()" style="color: red;">Logout</a>
</li>
</ul>
</nav>
<main class="container" style="padding: 0">
<form action="javascript:HandleSubmit();" style="margin: 0">
<fieldset id="form_fields">
<hgroup>
<h1>Add new shortlink</h1>
<h2><i style="color: red;">*</i> marks required fields</h2>
</hgroup>
<label for="linkname">Shortlink Name (leave empty for random)</label>
<input type="text" name="linkname" id="linkname" placeholder="shortlink">
<label for="link">Link *</label> <label for="link">Link <i style="color: red;">*</i></label>
<input type="text" name="link" id="link" placeholder="https://" style="width: 100%" onchange="HandleChange()"> <input type="text" name="link" id="link" placeholder="https://" onchange="HandleChange()">
<label for="description">Description</label> <label for="description">Description</label>
<input type="text" name="description" id="description" placeholder="" style="width: 100%"> <input type="text" name="description" id="description" placeholder="">
<input type="submit" id="submit" value="Login" onclick="HandleSubmit()" disabled> <div>
</fieldset>
<input type="submit" id="submit" value="Add" style="margin-top: 1em;">
</div>
</fieldset>
<dialog id="dialog-info">
<h2 id="dialog-heading"></h2>
<p id="dialog-text"></p>
<form method="dialog">
<button>Close</button>
</form>
</dialog>
<dialog id="dialog-info">
<h2 id="dialog-heading"></h2>
<p id="dialog-text"></p>
<form method="dialog">
<button>Close</button>
</form> </form>
</dialog> </main>
{{template "partials/footer" .}}
</form>
<footer>
<p>go-urlsh - <a href="/">Home</a> -
<a href="https://codeberg.org/lauralani/go-urlsh" target="_blank">Source Code</a> -
<a href="https://codeberg.org/lauralani/go-urlsh/src/branch/main/LICENSE" target="_blank">License</a>
</p>
</footer>
<script src="/admin/links.js"></script>
</body> </body>
</html>
</html>

74
web/custom.css Normal file
View file

@ -0,0 +1,74 @@
/* Grid */
body>main {
display: flex;
flex-direction: column;
justify-content: center;
min-height: calc(100vh - 7rem);
padding: 1rem 0;
}
article {
padding: 0;
overflow: hidden;
}
article div {
padding: 1rem;
}
@media (min-width: 576px) {
body>main {
padding: 1.25rem 0;
}
article div {
padding: 1.25rem;
}
}
@media (min-width: 768px) {
body>main {
padding: 1.5rem 0;
}
article div {
padding: 1.5rem;
}
}
@media (min-width: 992px) {
body>main {
padding: 1.75rem 0;
}
article div {
padding: 1.75rem;
}
}
@media (min-width: 1200px) {
body>main {
padding: 2rem 0;
}
article div {
padding: 2rem;
}
}
/* Nav */
summary[role="link"].secondary:is([aria-current], :hover, :active, :focus) {
background-color: transparent;
color: var(--secondary-hover);
}
@media (min-width: 992px) {
.grid>div:nth-of-type(2) {
display: block;
}
}
/* Footer */
body>footer {
padding: 1rem 0;
}

74
web/link_edit.html Normal file
View file

@ -0,0 +1,74 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset='utf-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<title>Edit Shortlink - go-urlsh</title>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<link rel="stylesheet" href="/admin/pico.min.css">
<link rel="stylesheet" href="/admin/custom.css">
<script src="/admin/link_add.js" defer></script>
<script src="/admin/misc.js" defer></script>
</head>
<body>
<nav class="container-fluid">
<ul>
<li>
<a href="/admin/" class="contrast"><strong>go-urlsh</strong></a>
</li>
</ul>
<ul>
<li>
<a href="/admin/">Links</a>
</li>
<li>
<a href="/admin/apikeys/">API Keys</a>
</li>
<li>
<a href="javascript: void(0)" >Users (coming soon)</a>
</li>
<li>
<a href="javascript: Logout()" style="color: red;">Logout</a>
</li>
</ul>
</nav>
<main class="container" style="padding: 0">
<form action="javascript:HandleSubmit();" style="margin: 0">
<fieldset id="form_fields">
<hgroup>
<h1>Edit shortlink</h1>
<h2><i style="color: red;">*</i> marks required fields</h2>
</hgroup>
<label for="linkname">Shortlink Name (to change this, delete the shortlink and add it again)</label>
<input type="text" name="linkname" id="linkname" value="{{.ID}}" data-tooltip="" readonly>
<label for="link">Link <i style="color: red;">*</i></label>
<input type="text" name="link" id="link" value="{{.URL}}">
<label for="description">Description</label>
<input type="text" name="description" id="description" value="{{.Description}}">
<div>
<input type="submit" id="submit" value="Save" style="margin-top: 1em;">
</div>
</fieldset>
<dialog id="dialog-info">
<h2 id="dialog-heading"></h2>
<p id="dialog-text"></p>
<form method="dialog">
<button>Close</button>
</form>
</dialog>
</form>
</main>
{{template "partials/footer" .}}
</body>
</html>

View file

@ -1,54 +1,77 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset='utf-8'> <meta charset='utf-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'> <meta http-equiv='X-UA-Compatible' content='IE=edge'>
<title>Shortlinks - go-urlsh</title> <title>Shortlinks - go-urlsh</title>
<meta name='viewport' content='width=device-width, initial-scale=1'> <meta name='viewport' content='width=device-width, initial-scale=1'>
<link rel="stylesheet" href="/admin/style.css"> <link rel="stylesheet" href="/admin/pico.min.css">
<link rel="stylesheet" href="/admin/custom.css">
<script src="/admin/links.js" defer></script>
<script src="/admin/misc.js" defer></script>
<style>
td {
vertical-align: middle;
text-align: left;
}
</style>
</head> </head>
<body>
<table> <body>
<thead> <nav class="container-fluid">
<tr> <ul>
<th>Shortlink</th> <li>
<th>URL</th> <a href="/admin/" class="contrast"><strong>go-urlsh</strong></a>
<th> </th> </li>
<th> </th> </ul>
</tr> <ul>
</thead> <li>
<tbody> <a href="/admin/links/new" style="color: greenyellow;">Add new Shortlink</a>
</li>
<li>
<a href="/admin/apikeys/">API Keys</a>
</li>
<li>
<a href="javascript: void(0)" >Users (coming soon)</a>
</li>
<li>
<a href="javascript: Logout()" style="color: red;">Logout</a>
</li>
</ul>
</nav>
<main class="container">
<table class="n-table">
<thead>
<tr>
<th>Shortlink</th>
<th>URL</th>
<th> </th>
<th> </th>
</tr>
</thead>
<tbody>
{{range .}} {{range .}}
<tr> <tr>
<td><a onclick="HandleCopy('{{.id}}')">{{.ID}}</a></td> <td><a href="javascript: HandleCopy('{{.ID}}');" data-tooltip="click to copy">{{.ID}}</a></td>
<td><a href="{{.URL}}" target="_blank">{{.URL}}</a></td> <td><a href="{{.URL}}" target="_blank" {{if .Description}}data-tooltip="{{.Description}}"{{end}}>{{.URL}}</a></td>
<td style="text-align: right;">
<td> <a href="/admin/links/edit/{{.ID}}">
<button type="button" id="edit-button" onclick="HandleEdit('{{.ID}}')"> Edit
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"><path stroke-linecap="round" stroke-linejoin="round" d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L10.582 16.07a4.5 4.5 0 01-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 011.13-1.897l8.932-8.931zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0115.75 21H5.25A2.25 2.25 0 013 18.75V8.25A2.25 2.25 0 015.25 6H10" /></svg> </a>
</button>
</td> </td>
<td> <td style="text-align: right;">
<button type="button" id="delete-button" onclick="HandleDelete('{{.ID}}')"> <a href="javascript: HandleDelete('{{.ID}}');">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"><path stroke-linecap="round" stroke-linejoin="round" d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0" /></svg> Delete
</button> </a>
</td> </td>
</tr> </tr>
{{end}} {{end}}
</tbody> </tbody>
</table> </table>
</main>
{{template "partials/footer" .}}
<footer>
<p>go-urlsh - <a href="/">Home</a> -
<a href="https://codeberg.org/lauralani/go-urlsh" target="_blank">Source Code</a> -
<a href="https://codeberg.org/lauralani/go-urlsh/src/branch/main/LICENSE" target="_blank">License</a>
</p>
</footer>
<script src="/admin/links.js"></script>
</body> </body>
</html>
</html>

4
web/misc.js Normal file
View file

@ -0,0 +1,4 @@
function Logout() {
document.cookie = 'gourlsh_auth=; Max-Age=-1; path=/; domain=' + location.hostname;
document.location = "/admin/login"
}

5
web/pico.classless.min.css vendored Normal file

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

5
web/pico.min.css vendored Normal file

File diff suppressed because one or more lines are too long

BIN
web/pico.min.css.gz Normal file

Binary file not shown.

1
web/pico.min.css.map Normal file

File diff suppressed because one or more lines are too long

BIN
web/pico.min.css.map.gz Normal file

Binary file not shown.

File diff suppressed because it is too large Load diff

Binary file not shown.