feat(router,templates): add interactions to page via editor
This commit is contained in:
102
router/editor.go
102
router/editor.go
@@ -5,7 +5,9 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"forge.capytal.company/capytalcode/project-comicverse/internals/randstr"
|
||||
"forge.capytal.company/capytalcode/project-comicverse/service"
|
||||
"forge.capytal.company/loreddev/x/smalltrip/exception"
|
||||
)
|
||||
@@ -14,6 +16,7 @@ func (router *router) pages(w http.ResponseWriter, r *http.Request) {
|
||||
router.assert.NotNil(w)
|
||||
router.assert.NotNil(r)
|
||||
|
||||
// TODO: Check if project exists
|
||||
id := r.PathValue("ID")
|
||||
if id == "" {
|
||||
exception.
|
||||
@@ -136,3 +139,102 @@ func (router *router) deletePage(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
http.Redirect(w, r, fmt.Sprintf("/projects/%s/", id), http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func (router *router) interactions(w http.ResponseWriter, r *http.Request) {
|
||||
router.assert.NotNil(w)
|
||||
router.assert.NotNil(r)
|
||||
|
||||
// TODO: Check if the project exists
|
||||
id := r.PathValue("ID")
|
||||
if id == "" {
|
||||
exception.
|
||||
BadRequest(fmt.Errorf(`a valid path value of "ID" must be provided`)).
|
||||
ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: Check if page exists
|
||||
pageID := r.PathValue("PageID")
|
||||
if pageID == "" {
|
||||
exception.
|
||||
BadRequest(fmt.Errorf(`a valid path value of "PageID" must be provided`)).
|
||||
ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
interactionID := r.PathValue("InteractionID")
|
||||
|
||||
switch getMethod(r) {
|
||||
case http.MethodPost:
|
||||
router.addInteraction(w, r)
|
||||
|
||||
default:
|
||||
exception.
|
||||
MethodNotAllowed([]string{
|
||||
http.MethodPost,
|
||||
}).
|
||||
ServeHTTP(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
func (router *router) addInteraction(w http.ResponseWriter, r *http.Request) {
|
||||
router.assert.NotNil(w)
|
||||
router.assert.NotNil(r)
|
||||
router.assert.NotNil(router.service)
|
||||
|
||||
id := r.PathValue("ID")
|
||||
router.assert.NotZero(id, "This method should be used after the path values are checked")
|
||||
|
||||
pageID := r.PathValue("PageID")
|
||||
router.assert.NotZero(pageID, "This method should be used after the path values are checked")
|
||||
|
||||
// TODO: Methods to manipulate interactions, instead of router need to do this logic
|
||||
page, err := router.service.GetPage(id, pageID)
|
||||
if err != nil {
|
||||
exception.InternalServerError(err).ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
page.Image = nil // HACK: Prevent image update on S3
|
||||
|
||||
x, err := strconv.ParseUint(r.FormValue("x"), 10, 0)
|
||||
if err != nil {
|
||||
exception.
|
||||
BadRequest(errors.Join(errors.New(`value "x" should be a valid non-negative integer`), err)).
|
||||
ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
y, err := strconv.ParseUint(r.FormValue("y"), 10, 0)
|
||||
if err != nil {
|
||||
exception.
|
||||
BadRequest(errors.Join(errors.New(`value "y" should be a valid non-negative integer`), err)).
|
||||
ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
link := r.FormValue("link")
|
||||
if link == "" {
|
||||
exception.BadRequest(errors.New(`missing parameter "link" in request`)).ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
intID, err := randstr.NewHex(6)
|
||||
if err != nil {
|
||||
exception.InternalServerError(err).ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
page.Interactions[intID] = service.PageInteraction{
|
||||
X: uint16(x),
|
||||
Y: uint16(y),
|
||||
URL: link,
|
||||
}
|
||||
|
||||
err = router.service.UpdatePage(id, page)
|
||||
if err != nil {
|
||||
exception.InternalServerError(err).ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
http.Redirect(w, r, fmt.Sprintf("/projects/%s/", id), http.StatusSeeOther)
|
||||
}
|
||||
|
||||
|
||||
@@ -99,6 +99,8 @@ func (router *router) setup() http.Handler {
|
||||
r.HandleFunc("/projects/{ID}/", router.projects)
|
||||
r.HandleFunc("/projects/{ID}/pages/{$}", router.pages)
|
||||
r.HandleFunc("/projects/{ID}/pages/{PageID}", router.pages)
|
||||
r.HandleFunc("/projects/{ID}/pages/{PageID}/interactions/{$}", router.interactions)
|
||||
r.HandleFunc("/projects/{ID}/pages/{PageID}/interactions/{InteractionID}", router.interactions)
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
@@ -7,10 +7,37 @@
|
||||
</nav>
|
||||
<main class="overflow-y-scroll flex justify-center col-span-3 py-20">
|
||||
<div class="flex flex-col gap-10 h-fit">
|
||||
{{range $pageID, $page := .Pages}}
|
||||
<section id="{{$pageID}}" class="bg-blue-500 w-100">
|
||||
<img src="/projects/{{$.ID}}/pages/{{$pageID}}/">
|
||||
<form action="/projects/{{$.ID}}/pages/{{$pageID}}/" method="post">
|
||||
{{range $page := .Pages}}
|
||||
<section id="{{$page.ID}}" class="bg-blue-500 w-100">
|
||||
<!--
|
||||
INFO: The interaction form could be another page that is shown
|
||||
when "Add Interaction" is clicked. Said page could be also a partial
|
||||
than can replace the current image using htmx, so it is
|
||||
compatible with JavaScript enabled or not.
|
||||
-->
|
||||
<form action="/projects/{{$.ID}}/pages/{{$page.ID}}/interactions/" method="post">
|
||||
<div class="flex">
|
||||
<div class="relative flex">
|
||||
<div class="absolute z-2 w-full h-full top-0 left-0">
|
||||
{{range $key, $interaction := $page.Interactions}}
|
||||
<a class="absolute" href="{{$interaction.URL}}"
|
||||
style="top:{{$interaction.Y}}%;left:{{$interaction.X}}%;">
|
||||
<span
|
||||
class="bg-red-200 opacity-10 block w-10 h-10 transform -translate-x-[50%] -translate-y-[50%]"></span>
|
||||
</a>
|
||||
{{end}}
|
||||
</div>
|
||||
<img src="/projects/{{$.ID}}/pages/{{$page.ID}}/" class="z-1 relative">
|
||||
</div>
|
||||
<input type="range" min="0" max="100" name="y" style="writing-mode: vertical-lr;">
|
||||
</div>
|
||||
<input type="range" min="0" max="100" name="x" class="w-full">
|
||||
<input type="url" required name="link" class="bg-slate-300" placeholder="url of interaction">
|
||||
<button class="rounded-full bg-blue-700 p-1 px-3 text-sm text-slate-100">
|
||||
Add interaction
|
||||
</button>
|
||||
</form>
|
||||
<form action="/projects/{{$.ID}}/pages/{{$page.ID}}/" method="post">
|
||||
<input type="hidden" name="x-method" value="delete">
|
||||
<button class="rounded-full bg-red-700 p-1 px-3 text-sm text-slate-100">
|
||||
Delete
|
||||
|
||||
Reference in New Issue
Block a user