Skip to content

Commit 6c46f10

Browse files
committed
add alpine.js
1 parent b436b8a commit 6c46f10

File tree

8 files changed

+194
-16
lines changed

8 files changed

+194
-16
lines changed

config/app_config.go

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ type LogSetting struct {
1111
}
1212

1313
type WebServerSetting struct {
14+
Title string
1415
Host string
1516
BasePath string
1617
}

config/config.json

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"fileName": "go-note.log"
55
},
66
"web": {
7+
"title": "Note-X",
78
"host": "localhost:8888",
89
"basePath": "/"
910
}

internal/app/app_service.go

+55-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
package app
22

33
import (
4+
"crypto/rand"
5+
"errors"
6+
"fmt"
7+
"log/slog"
8+
"math/big"
9+
410
"github.com/ghostrepo00/go-note/config"
11+
"github.com/ghostrepo00/go-note/internal/pkg/model"
512
"github.com/supabase-community/supabase-go"
613
)
714

@@ -10,10 +17,57 @@ type appService struct {
1017
DbClient *supabase.Client
1118
}
1219

20+
type AppService interface {
21+
GetbyId(id string) (result []*model.FormData, err error)
22+
DeletebyId(id string) (err error)
23+
Save(data *model.FormData) error
24+
}
25+
1326
func NewAppService(appConfig *config.AppConfig, dbClient *supabase.Client) *appService {
1427
return &appService{appConfig, dbClient}
1528
}
1629

17-
func (r *appService) do() {
30+
func GenerateRandomId(length int) (string, error) {
31+
const letters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
32+
result := make([]byte, length)
33+
for i := 0; i < length; i++ {
34+
num, err := rand.Int(rand.Reader, big.NewInt(int64(len(letters))))
35+
if err != nil {
36+
return "", err
37+
}
38+
result[i] = letters[num.Int64()]
39+
}
40+
41+
return string(result), nil
42+
}
43+
44+
func (r *appService) GetbyId(id string) (result []*model.FormData, err error) {
45+
if id != "" {
46+
_, err = r.DbClient.From("notes").Select("id, content, password, is_encrypted", "", false).Eq("id", id).ExecuteTo(&result)
47+
fmt.Print(result, err)
48+
}
49+
return
50+
}
51+
52+
func (r *appService) DeletebyId(id string) (err error) {
53+
if id != "" {
54+
_, _, err = r.DbClient.From("notes").Delete("", "").Eq("id", id).Execute()
55+
}
56+
return
57+
}
58+
59+
func (r *appService) Save(data *model.FormData) (err error) {
60+
if data.Id == "" {
61+
if data.Id, err = GenerateRandomId(5); err == nil {
62+
a, cc, d := r.DbClient.From("notes").Select("id", "", false).Eq("id", data.Id).ExecuteString()
63+
slog.Info("", "a", a, "e", d, "c", cc)
64+
}
65+
}
1866

67+
if a, b, err := r.DbClient.From("notes").Upsert(&data, "", "", "").Execute(); err != nil {
68+
return errors.New("ssssssssssssssssssssssssss")
69+
} else {
70+
slog.Info("supabase", "a", a, "b", b, "c", err)
71+
}
72+
return nil
1973
}

internal/app/web_handler.go

+44-4
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,61 @@
11
package app
22

33
import (
4+
"log/slog"
45
"net/http"
56

67
"github.com/ghostrepo00/go-note/config"
8+
"github.com/ghostrepo00/go-note/internal/pkg/model"
79
"github.com/gin-gonic/gin"
810
)
911

1012
type webHandler struct {
1113
AppConfig *config.AppConfig
12-
Service *appService
14+
Service AppService
1315
}
1416

15-
func NewWebHandler(appConfig *config.AppConfig, service *appService) *webHandler {
17+
type WebHandler interface {
18+
Default(ctx *gin.Context)
19+
GetById(ctx *gin.Context)
20+
DeleteById(c *gin.Context)
21+
Save(ctx *gin.Context)
22+
}
23+
24+
func NewWebHandler(appConfig *config.AppConfig, service AppService) *webHandler {
1625
return &webHandler{appConfig, service}
1726
}
1827

19-
func (r *webHandler) Default(ctx *gin.Context) {
20-
ctx.HTML(http.StatusOK, "index.html", nil)
28+
func (r *webHandler) Default(c *gin.Context) {
29+
p := make(map[string]string)
30+
p["title"] = r.AppConfig.Web.Title
31+
c.HTML(http.StatusOK, "index.html", p)
32+
}
33+
34+
func (r *webHandler) GetById(c *gin.Context) {
35+
id := c.Param("id")
36+
slog.Info("request id", "id", id)
37+
a, _ := r.Service.GetbyId(id)
38+
data := make(map[string]string)
39+
data["content"] = a[0].Content
40+
data["id"] = a[0].Id
41+
c.HTML(http.StatusOK, "index.html", data)
42+
}
43+
44+
func (r *webHandler) DeleteById(c *gin.Context) {
45+
id := c.Param("id")
46+
r.Service.DeletebyId(id)
47+
slog.Info("request id", "id", id)
48+
c.Header("HX-Redirect", "/")
49+
}
50+
51+
func (r *webHandler) Save(c *gin.Context) {
52+
formData := &model.FormData{}
53+
c.Bind(formData)
54+
if err := r.Service.Save(formData); err != nil {
55+
slog.Error("error", err)
56+
c.AbortWithStatus(http.StatusInternalServerError)
57+
} else {
58+
c.Header("HX-Redirect", "/"+formData.Id)
59+
}
60+
slog.Info("request id", "id", formData.Id, "content", formData.Content)
2161
}

internal/app/web_server.go

+5-2
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,13 @@ func ConfigureWebRouter(router *gin.Engine, appConfig *config.AppConfig, dbClien
2727
router.Static("/assets", "web/assets")
2828
router.StaticFile("/favicon.ico", "web/favicon.ico")
2929

30-
service := NewAppService(appConfig, dbClient)
31-
handler := NewWebHandler(appConfig, service)
30+
var service AppService = NewAppService(appConfig, dbClient)
31+
var handler WebHandler = NewWebHandler(appConfig, service)
3232

3333
router.GET("", handler.Default)
34+
router.GET("/:id", handler.GetById)
35+
router.DELETE("/:id", handler.DeleteById)
36+
router.POST("/save", handler.Save)
3437
}
3538

3639
func (r *webServer) Run() {

internal/pkg/model/form_data.go

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package model
2+
3+
type FormData struct {
4+
Id string `form:"id" json:"id"`
5+
Content string `form:"content" json:"content"`
6+
Password string `form:"password" json:"password"`
7+
IsEncrypted bool `form:"isEncrypted" json:"is_encrypted"`
8+
}

web/assets/js/alpine.min.js

+5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

web/template/home/index.html

+75-9
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,90 @@
44
<meta charset="utf-8">
55
<meta name="viewport" content="width=device-width, initial-scale=1">
66
<title>{{ .title }}</title>
7-
<script src="/assets/js/htmx.min.js"></script>
7+
<script defer src="/assets/js/htmx.min.js"></script>
8+
<script defer src="/assets/js/alpine.min.js"></script>
89
<link href="/assets/style/tailwind.css" rel="stylesheet">
910
<link href="/assets/style/main.css" rel="stylesheet">
1011
</head>
11-
<body class="bg-base-800 text-base-500">
12+
<body class="bg-base-900 text-base-100">
1213
<div class="flex flex-col min-h-screen">
13-
<div class="p-2" hx-target="#content">
14-
<ul>
15-
<li><div hx-get="/default">Home</div></li>
16-
<li><div hx-get="/webtag">Webtag</div></li>
14+
<div class="p-2" hx-target="#content">
15+
<ul class="flex flex-wrap items-center justify-center text-gray-900 dark:text-white">
16+
<li>
17+
<a href="/" class="me-4 hover:underline md:me-6 ">Home</a>
18+
</li>
19+
<li>
20+
<a href="#" class="me-4 hover:underline md:me-6">Premium</a>
21+
</li>
1722
</ul>
1823
</div>
1924

20-
<div id="content" class="flex-grow p-2">
21-
25+
<div id="content" class="flex-grow flex flex-row p-2 w-full h-full">
26+
<div class="flex-none w-14 h-14">
27+
28+
</div>
29+
<div class="grow h-fit" x-data="{ content: '{{.content}}' }" x-init="$refs.contentx.textContent=content">
30+
<form hx-post="/save">
31+
<div x-ref="contentx" @input="content = $event.target.textContent" contenteditable="true" class="bg-base-600 w-1/12 min-h-fit overflow-y-auto"></div>
32+
<input title="=" type="hidden" name="content" x-model="content"/>
33+
<!-- <textarea title="content" cols="200" rows="30" class="p-2 border-none outline-none overflow-y-auto bg-base-700 bg-gradient-to-r bg-opacity-50"></textarea> -->
34+
<div class="flex gap-2">
35+
<label for="id">Url</label><input class="text-base-950" id="id" type="text" value="{{.id}}"/>
36+
<label for="password">Password</label><input class="text-base-950" id="password" type="text" value="{{.password}}"/>
37+
<input id="isEncrypted" type="checkbox" value="{{.isEncrypted}}"/><label for="isEncrypted">Encrypt</label>
38+
<button type="submit">Save</button>
39+
<button type="button" id="deleteButton">Delete</button>
40+
</div>
41+
</form>
42+
<dialog>
43+
<p>Greetings, one and all!</p>
44+
<form method="dialog">
45+
<button type="button" hx-trigger="click" hx-delete="/{{.id}}">OK</button>
46+
</form>
47+
</dialog>
48+
</div>
49+
<div class="flex-none w-14 h-14">
50+
51+
</div>
2252
</div>
2353

24-
<div class="p-2">footer</div>
54+
<div class="p-2">
55+
<ul class="flex flex-wrap items-center justify-center text-gray-900 dark:text-white">
56+
<li>
57+
<a href="#" class="me-4 hover:underline md:me-6">Contact</a>
58+
</li>
59+
</ul>
60+
</div>
2561
</div>
62+
<script>
63+
const counter = (function () {
64+
let privateCounter = 0;
65+
function changeBy(val) {
66+
privateCounter += val;
67+
}
68+
69+
const dialog = document.querySelector("dialog");
70+
const showButton = document.getElementById("deleteButton")
71+
72+
// "Show the dialog" button opens the dialog modally
73+
showButton.addEventListener("click", () => {
74+
dialog.showModal();
75+
});
76+
77+
return {
78+
increment() {
79+
changeBy(1);
80+
},
81+
82+
decrement() {
83+
changeBy(-1);
84+
},
85+
86+
value() {
87+
return privateCounter;
88+
},
89+
};
90+
})();
91+
</script>
2692
</body>
2793
</html>

0 commit comments

Comments
 (0)