Feat: styles and session
This commit is contained in:
		
							
								
								
									
										24
									
								
								components/createroomform.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								components/createroomform.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | |||||||
|  | {{define "createform"}} | ||||||
|  |  <div class="create-room-div"> | ||||||
|  |             Create a room <br/> | ||||||
|  |             or<br/> | ||||||
|  |             @CustomBtn(templ.Attributes{"hx-get": "/room/hideform", "hx-target": ".create-room-div"}, "Hide Form") | ||||||
|  |             <form hx-post="/room/create" hx-target="#ancestor"> | ||||||
|  |                 <label For="room_name">Room Name</label><br/> | ||||||
|  |                 <input type="text" id="room_name" name="room_name" class="text-center text-black" value={utils.MakeDefaultRoomName(utils.GetUsername(c))}/><br/> | ||||||
|  |                 <label For="game_time">Game Time:</label><br/> | ||||||
|  |                 <input type="number" id="game_time" name="game_time" class="text-center text-black" value="300"/><br/> | ||||||
|  |                 <label For="minority_number">Minority Number:</label><br/> | ||||||
|  |                 <input type="number" id="minority_number" name="minority_number" class="text-center text-black" value="1"/><br/> | ||||||
|  |                 <label For="language">Language:</label><br/> | ||||||
|  |                 /* <input type="text" id="language" name="language" class="text-center text-black" value="en"/><br/> */ | ||||||
|  |                 @base.LangOption()<br/> | ||||||
|  |                 <label For="password">Password:</label><br/> | ||||||
|  |                 <input type="text" id="password" name="room_pass" class="text-center text-black" value="" placeholder="Leave empty for open room"/><br/> | ||||||
|  |                 @CustomBtn(templ.Attributes{"type": "submit"}, "Create Room") | ||||||
|  |             </form> | ||||||
|  |         </div> | ||||||
|  |         <div class="create-room-div"> | ||||||
|  |             Hello, you should login. | ||||||
|  |         </div> | ||||||
|  | {{end}} | ||||||
| @@ -2,14 +2,48 @@ | |||||||
| <!DOCTYPE html> | <!DOCTYPE html> | ||||||
| <html lang="en"> | <html lang="en"> | ||||||
| <head> | <head> | ||||||
| 	<meta charset="UTF-8"> |  | ||||||
| 	<meta name="viewport" content="width=device-width, initial-scale=1.0"> |  | ||||||
| 	<title>Word Colors</title> | 	<title>Word Colors</title> | ||||||
| 	<script src="https://unpkg.com/htmx.org@2.0.4" integrity="sha384-HGfztofotfshcF7+8n44JQL2oJmowVChPTg48S+jvZoztPfvwD79OC/LTtG6dMp+" crossorigin="anonymous"></script> | 	<script src="https://unpkg.com/htmx.org@2.0.4" integrity="sha384-HGfztofotfshcF7+8n44JQL2oJmowVChPTg48S+jvZoztPfvwD79OC/LTtG6dMp+" crossorigin="anonymous"></script> | ||||||
|  | 	<script src="/assets/htmx.min.js"></script> | ||||||
|  | 	<script src="/assets/htmx.sse.js"></script> | ||||||
|  | 	<link rel="stylesheet" href="/assets/style.css"/> | ||||||
|  | 	<meta charset="utf-8" name="viewport" content="width=device-width,initial-scale=1"/> | ||||||
|  | 	<link rel="icon" sizes="64x64" href="favicon.ico"/> | ||||||
|  | 	<style type="text/css"> | ||||||
|  | 		body{ | ||||||
|  |             background-color: #0C1616FF; | ||||||
|  |             color: #8896b2; | ||||||
|  |             max-width: 800px; | ||||||
|  |             min-width: 0; | ||||||
|  |             margin: 2em auto !important; | ||||||
|  |             margin-left: auto; | ||||||
|  |             margin-right: auto; | ||||||
|  |             line-height: 1.5; | ||||||
|  |             font-size: 16px; | ||||||
|  |             font-family: Open Sans,Arial; | ||||||
|  |             text-align: center; | ||||||
|  |             display: block; | ||||||
|  |         } | ||||||
|  |         a{ | ||||||
|  |             color: #00a2e7; | ||||||
|  |         } | ||||||
|  |         a:visited{ | ||||||
|  |             color: #ca1a70; | ||||||
|  |         } | ||||||
|  |         table { | ||||||
|  |           border-collapse: separate !important; | ||||||
|  |           border-spacing: 10px 10px; | ||||||
|  |           border: 1px solid white; | ||||||
|  |         } | ||||||
|  |         tr{ | ||||||
|  |             border: 1px solid white; | ||||||
|  |         } | ||||||
|  | 	</style> | ||||||
| </head> | </head> | ||||||
| <body> | <body> | ||||||
| <div id=ancestor> | <div id=ancestor> | ||||||
| 	{{template "login"}} | 	{{template "login"}} | ||||||
|  | 	    <button button id="create-form-btn" type="submit" class="justify-center rounded-md bg-indigo-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600" hx-get="/room/createform" hx-swap="outerHTML">SHOW ROOM CREATE FORM</button> | ||||||
| 	<h1>Word Color Cards</h1> | 	<h1>Word Color Cards</h1> | ||||||
| 	<div style="display: flex; gap: 1rem; flex-wrap: wrap; padding: 1rem;"> | 	<div style="display: flex; gap: 1rem; flex-wrap: wrap; padding: 1rem;"> | ||||||
| 		{{range $word, $color := .}} | 		{{range $word, $color := .}} | ||||||
|   | |||||||
							
								
								
									
										10
									
								
								handlers/actions.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								handlers/actions.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | package handlers | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"context" | ||||||
|  | 	"golias/models" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func createRoom(ctx context.Context, req *models.RoomReq) (*models.RoomPublic, error) { | ||||||
|  | 	return nil, nil | ||||||
|  | } | ||||||
| @@ -1,10 +1,12 @@ | |||||||
| package handlers | package handlers | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
|  | 	"context" | ||||||
| 	"crypto/hmac" | 	"crypto/hmac" | ||||||
| 	"crypto/sha256" | 	"crypto/sha256" | ||||||
| 	"encoding/base64" | 	"encoding/base64" | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
|  | 	"errors" | ||||||
| 	"golias/models" | 	"golias/models" | ||||||
| 	"golias/utils" | 	"golias/utils" | ||||||
| 	"html/template" | 	"html/template" | ||||||
| @@ -112,3 +114,12 @@ func cacheSetSession(key string, session *models.Session) error { | |||||||
| 	memcache.Expire(key, 10*60) | 	memcache.Expire(key, 10*60) | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func updateRoomInSession(ctx context.Context, roomID string) (context.Context, error) { | ||||||
|  | 	s, ok := ctx.Value("session").(models.Session) | ||||||
|  | 	if !ok { | ||||||
|  | 		return context.TODO(), errors.New("failed to extract session from ctx") | ||||||
|  | 	} | ||||||
|  | 	s.CurrentRoom = roomID | ||||||
|  | 	return context.WithValue(ctx, "session", s), nil | ||||||
|  | } | ||||||
|   | |||||||
							
								
								
									
										15
									
								
								handlers/elements.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								handlers/elements.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | |||||||
|  | package handlers | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"html/template" | ||||||
|  | 	"net/http" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func HandleShowCreateForm(w http.ResponseWriter, r *http.Request) { | ||||||
|  | 	tmpl, err := template.ParseGlob("components/*.html") | ||||||
|  | 	if err != nil { | ||||||
|  | 		abortWithError(w, err.Error()) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	tmpl.ExecuteTemplate(w, "createform", nil) | ||||||
|  | } | ||||||
							
								
								
									
										44
									
								
								handlers/game.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								handlers/game.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,44 @@ | |||||||
|  | package handlers | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"context" | ||||||
|  | 	"golias/models" | ||||||
|  | 	"html/template" | ||||||
|  | 	"net/http" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func HandleCreateRoom(w http.ResponseWriter, r *http.Request) { | ||||||
|  | 	// parse payload | ||||||
|  | 	payload := &models.RoomReq{ | ||||||
|  | 		RoomPass: r.PostFormValue("room_pass"), | ||||||
|  | 		RoomName: r.PostFormValue("room_name"), | ||||||
|  | 	} | ||||||
|  | 	// create a room | ||||||
|  | 	room, err := createRoom(r.Context(), payload) | ||||||
|  | 	if err != nil { | ||||||
|  | 		msg := "failed to create a room" | ||||||
|  | 		log.Error(msg, "error", err) | ||||||
|  | 		abortWithError(w, msg) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	ctx := context.WithValue(r.Context(), "current_room", room.ID) | ||||||
|  | 	ctx, err = updateRoomInSession(ctx, room.ID) | ||||||
|  | 	if err != nil { | ||||||
|  | 		msg := "failed to set current room to session" | ||||||
|  | 		log.Error(msg, "error", err) | ||||||
|  | 		abortWithError(w, msg) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	// send msg of created room | ||||||
|  | 	// h.Broker.Notifier <- broker.NotificationEvent{ | ||||||
|  | 	// 	EventName: models.MsgRoomListUpdate, | ||||||
|  | 	// 	Payload:   fmt.Sprintf("%s created a room named %s", r.CreatorName, r.RoomName), | ||||||
|  | 	// } | ||||||
|  | 	// return html | ||||||
|  | 	tmpl, err := template.ParseGlob("components/*.html") | ||||||
|  | 	if err != nil { | ||||||
|  | 		abortWithError(w, err.Error()) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	tmpl.ExecuteTemplate(w, "main", nil) | ||||||
|  | } | ||||||
| @@ -1,19 +1,27 @@ | |||||||
| package handlers | package handlers | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
|  | 	"golias/config" | ||||||
|  | 	"golias/pkg/cache" | ||||||
| 	"html/template" | 	"html/template" | ||||||
| 	"log/slog" | 	"log/slog" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"os" | 	"os" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| var log *slog.Logger | var ( | ||||||
|  | 	log      *slog.Logger | ||||||
|  | 	cfg      *config.Config | ||||||
|  | 	memcache cache.Cache | ||||||
|  | ) | ||||||
|  |  | ||||||
| func init() { | func init() { | ||||||
| 	log = slog.New(slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{ | 	log = slog.New(slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{ | ||||||
| 		Level:     slog.LevelDebug, | 		Level:     slog.LevelDebug, | ||||||
| 		AddSource: true, | 		AddSource: true, | ||||||
| 	})) | 	})) | ||||||
|  | 	memcache = cache.MemCache | ||||||
|  | 	cfg = config.LoadConfigOrDefault("") | ||||||
| } | } | ||||||
|  |  | ||||||
| var roundWords = map[string]string{ | var roundWords = map[string]string{ | ||||||
|   | |||||||
| @@ -6,17 +6,10 @@ import ( | |||||||
| 	"crypto/sha256" | 	"crypto/sha256" | ||||||
| 	"encoding/base64" | 	"encoding/base64" | ||||||
| 	"errors" | 	"errors" | ||||||
| 	"golias/config" |  | ||||||
| 	"golias/pkg/cache" |  | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"time" | 	"time" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| var ( |  | ||||||
| 	cfg      config.Config |  | ||||||
| 	memcache cache.Cache |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // responseWriterWrapper wraps http.ResponseWriter to capture status code | // responseWriterWrapper wraps http.ResponseWriter to capture status code | ||||||
| type responseWriterWrapper struct { | type responseWriterWrapper struct { | ||||||
| 	http.ResponseWriter | 	http.ResponseWriter | ||||||
| @@ -99,6 +92,8 @@ func GetSession(next http.Handler) http.Handler { | |||||||
| 		} | 		} | ||||||
| 		ctx := context.WithValue(r.Context(), | 		ctx := context.WithValue(r.Context(), | ||||||
| 			"username", userSession.Username) | 			"username", userSession.Username) | ||||||
|  | 		ctx = context.WithValue(r.Context(), | ||||||
|  | 			"session", userSession) | ||||||
| 		if err := cacheSetSession(sessionToken, | 		if err := cacheSetSession(sessionToken, | ||||||
| 			userSession); err != nil { | 			userSession); err != nil { | ||||||
| 			msg := "failed to marshal user session" | 			msg := "failed to marshal user session" | ||||||
|   | |||||||
							
								
								
									
										7
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								main.go
									
									
									
									
									
								
							| @@ -1,8 +1,8 @@ | |||||||
| package main | package main | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"fmt" |  | ||||||
| 	"golias/handlers" | 	"golias/handlers" | ||||||
|  | 	"log/slog" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"time" | 	"time" | ||||||
| ) | ) | ||||||
| @@ -22,13 +22,14 @@ func ListenToRequests(port string) error { | |||||||
|  |  | ||||||
| 	mux.HandleFunc("GET /ping", handlers.HandlePing) | 	mux.HandleFunc("GET /ping", handlers.HandlePing) | ||||||
| 	mux.HandleFunc("GET /", handlers.HandleHome) | 	mux.HandleFunc("GET /", handlers.HandleHome) | ||||||
| 	fmt.Println("Listening", "addr", port) | 	mux.HandleFunc("POST /login", handlers.HandleFrontLogin) | ||||||
|  | 	mux.HandleFunc("GET /room/createform", handlers.HandleShowCreateForm) | ||||||
|  | 	slog.Info("Listening", "addr", port) | ||||||
| 	return server.ListenAndServe() | 	return server.ListenAndServe() | ||||||
| } | } | ||||||
|  |  | ||||||
| func main() { | func main() { | ||||||
| 	port := ":3000" | 	port := ":3000" | ||||||
| 	fmt.Printf("Starting server on %s\n", port) |  | ||||||
| 	err := ListenToRequests(port) | 	err := ListenToRequests(port) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		panic(err) | 		panic(err) | ||||||
|   | |||||||
| @@ -67,3 +67,12 @@ type GameSettings struct { | |||||||
| 	ProgressPct uint32 `json:"progress_pct"` | 	ProgressPct uint32 `json:"progress_pct"` | ||||||
| 	IsOver      bool | 	IsOver      bool | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // ===== | ||||||
|  |  | ||||||
|  | type RoomReq struct { | ||||||
|  | 	// is not user or not unique | ||||||
|  | 	RoomPass string `json:"room_pass" form:"room_pass"` | ||||||
|  | 	RoomName string `json:"room_name" form:"room_name"` | ||||||
|  | 	// GameSettings | ||||||
|  | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Grail Finder
					Grail Finder