Grouping route

This commit is contained in:
2024-10-02 15:33:41 +07:00
parent 5d7dc70f1b
commit 93c44f40cc
41 changed files with 1176 additions and 1158 deletions

View File

@ -7,8 +7,8 @@ import (
"errors"
"fmt"
"github.com/fossyy/filekeeper/app"
"github.com/fossyy/filekeeper/view/client/auth/forgotPassword"
"github.com/fossyy/filekeeper/view/client/email"
"github.com/fossyy/filekeeper/view/client/forgotPassword"
"github.com/google/uuid"
"github.com/redis/go-redis/v9"
"net/http"
@ -130,7 +130,7 @@ func verifyForgot(user *models.User) error {
}
var buffer bytes.Buffer
err = emailView.ForgotPassword(user.Username, fmt.Sprintf("https://%s/forgot-password/verify/%s", utils.Getenv("DOMAIN"), code)).Render(context.Background(), &buffer)
err = emailView.ForgotPassword(user.Username, fmt.Sprintf("https://%s/auth/forgot-password/verify/%s", utils.Getenv("DOMAIN"), code)).Render(context.Background(), &buffer)
if err != nil {
return err
}

View File

@ -4,22 +4,16 @@ import (
"encoding/json"
"errors"
"github.com/fossyy/filekeeper/app"
forgotPasswordHandler "github.com/fossyy/filekeeper/handler/forgotPassword"
"github.com/fossyy/filekeeper/handler/auth/forgotPassword"
"github.com/fossyy/filekeeper/session"
"github.com/fossyy/filekeeper/types"
"github.com/fossyy/filekeeper/utils"
"github.com/fossyy/filekeeper/view/client/forgotPassword"
signupView "github.com/fossyy/filekeeper/view/client/signup"
"github.com/fossyy/filekeeper/view/client/auth/forgotPassword"
signupView "github.com/fossyy/filekeeper/view/client/auth/signup"
"github.com/redis/go-redis/v9"
"net/http"
)
func init() {
//TESTING
}
func GET(w http.ResponseWriter, r *http.Request) {
code := r.PathValue("code")

View File

@ -48,21 +48,22 @@ func GET(w http.ResponseWriter, r *http.Request) {
_, err := app.Server.Cache.GetCache(r.Context(), "CsrfTokens:"+r.URL.Query().Get("state"))
if err != nil {
if errors.Is(err, redis.Nil) {
http.Redirect(w, r, fmt.Sprintf("/signin?error=%s", "csrf_token_error"), http.StatusFound)
http.Redirect(w, r, fmt.Sprintf("/auth/signin?error=%s", "csrf_token_error"), http.StatusFound)
return
}
app.Server.Logger.Error(err.Error())
w.WriteHeader(http.StatusInternalServerError)
return
}
err = app.Server.Cache.DeleteCache(r.Context(), "CsrfTokens:"+r.URL.Query().Get("state"))
if err != nil {
http.Redirect(w, r, fmt.Sprintf("/signin?error=%s", "csrf_token_error"), http.StatusFound)
http.Redirect(w, r, fmt.Sprintf("/auth/signin?error=%s", "csrf_token_error"), http.StatusFound)
return
}
if err := r.URL.Query().Get("error"); err != "" {
http.Redirect(w, r, fmt.Sprintf("/signin?error=%s", err), http.StatusFound)
http.Redirect(w, r, fmt.Sprintf("/auth/signin?error=%s", err), http.StatusFound)
return
}

View File

@ -9,7 +9,7 @@ import (
"github.com/fossyy/filekeeper/types/models"
"github.com/fossyy/filekeeper/utils"
"github.com/fossyy/filekeeper/view/client/auth"
signupView "github.com/fossyy/filekeeper/view/client/signup"
signupView "github.com/fossyy/filekeeper/view/client/auth/signup"
"github.com/google/uuid"
"github.com/redis/go-redis/v9"
"net/http"
@ -27,7 +27,7 @@ func GET(w http.ResponseWriter, r *http.Request) {
_, err := app.Server.Cache.GetCache(r.Context(), "GoogleSetup:"+code)
if err != nil {
if errors.Is(err, redis.Nil) {
http.Redirect(w, r, "/signup", http.StatusSeeOther)
http.Redirect(w, r, "/auth/signup", http.StatusSeeOther)
return
}
w.WriteHeader(http.StatusInternalServerError)

View File

@ -7,7 +7,7 @@ import (
"github.com/fossyy/filekeeper/session"
"github.com/fossyy/filekeeper/types"
"github.com/fossyy/filekeeper/utils"
"github.com/fossyy/filekeeper/view/client/signin"
"github.com/fossyy/filekeeper/view/client/auth/signin"
"net/http"
)

View File

@ -8,8 +8,8 @@ import (
"fmt"
"github.com/fossyy/filekeeper/app"
"github.com/fossyy/filekeeper/utils"
signupView "github.com/fossyy/filekeeper/view/client/auth/signup"
"github.com/fossyy/filekeeper/view/client/email"
signupView "github.com/fossyy/filekeeper/view/client/signup"
"github.com/redis/go-redis/v9"
"net/http"
"time"
@ -117,7 +117,7 @@ func verifyEmail(user *models.User) error {
code = storedCode
}
err = emailView.RegistrationEmail(user.Username, fmt.Sprintf("https://%s/signup/verify/%s", utils.Getenv("DOMAIN"), code)).Render(context.Background(), &buffer)
err = emailView.RegistrationEmail(user.Username, fmt.Sprintf("https://%s/auth/signup/verify/%s", utils.Getenv("DOMAIN"), code)).Render(context.Background(), &buffer)
if err != nil {
return err
}

View File

@ -5,8 +5,8 @@ import (
"encoding/json"
"errors"
"github.com/fossyy/filekeeper/app"
signupHandler "github.com/fossyy/filekeeper/handler/signup"
signupView "github.com/fossyy/filekeeper/view/client/signup"
"github.com/fossyy/filekeeper/handler/auth/signup"
signupView "github.com/fossyy/filekeeper/view/client/auth/signup"
"github.com/redis/go-redis/v9"
"net/http"

View File

@ -39,6 +39,6 @@ func GET(w http.ResponseWriter, r *http.Request) {
MaxAge: -1,
})
http.Redirect(w, r, "/signin", http.StatusSeeOther)
http.Redirect(w, r, "/auth/signin", http.StatusSeeOther)
return
}

View File

@ -58,6 +58,6 @@ func POST(w http.ResponseWriter, r *http.Request) {
return
}
http.Redirect(w, r, "/signin", http.StatusSeeOther)
http.Redirect(w, r, "/auth/signin", http.StatusSeeOther)
return
}

View File

@ -1,67 +1,22 @@
package userHandler
import (
"context"
"encoding/json"
"errors"
"fmt"
"github.com/a-h/templ"
"github.com/fossyy/filekeeper/app"
"github.com/fossyy/filekeeper/session"
"github.com/fossyy/filekeeper/types"
"github.com/fossyy/filekeeper/types/models"
"github.com/fossyy/filekeeper/utils"
"github.com/fossyy/filekeeper/view/client/user"
"github.com/google/uuid"
"github.com/gorilla/websocket"
"gorm.io/gorm"
"net/http"
"strings"
)
var errorMessages = map[string]string{
"password_not_match": "The passwords provided do not match. Please try again.",
}
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
}
type ActionType string
const (
UploadNewFile ActionType = "UploadNewFile"
DeleteFile ActionType = "DeleteFile"
Ping ActionType = "Ping"
)
type WebsocketAction struct {
Action ActionType `json:"action"`
}
type ActionUploadNewFile struct {
Action string `json:"action"`
Name string `json:"name"`
Size uint64 `json:"size"`
Chunk uint64 `json:"chunk"`
StartHash string `json:"startHash"`
EndHash string `json:"endHash"`
RequestID string `json:"requestID"`
}
func GET(w http.ResponseWriter, r *http.Request) {
userSession := r.Context().Value("user").(types.User)
if r.Header.Get("upgrade") == "websocket" {
upgrade, err := upgrader.Upgrade(w, r, nil)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
handlerWS(upgrade, userSession)
}
sessions, err := session.GetSessions(userSession.Email)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
@ -126,168 +81,3 @@ func GET(w http.ResponseWriter, r *http.Request) {
return
}
}
func handlerWS(conn *websocket.Conn, userSession types.User) {
defer conn.Close()
var err error
var message []byte
for {
_, message, err = conn.ReadMessage()
if err != nil {
if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
app.Server.Logger.Error("Unexpected connection closure:", err)
} else {
app.Server.Logger.Error("Connection closed:", err)
}
return
}
var action WebsocketAction
err = json.Unmarshal(message, &action)
if err != nil {
app.Server.Logger.Error("Error unmarshalling WebsocketAction:", err)
sendErrorResponse(conn, action.Action, "Internal Server Error")
continue
}
switch action.Action {
case UploadNewFile:
var uploadNewFile ActionUploadNewFile
err = json.Unmarshal(message, &uploadNewFile)
if err != nil {
app.Server.Logger.Error("Error unmarshalling ActionUploadNewFile:", err)
sendErrorResponse(conn, action.Action, "Internal Server Error")
continue
}
var file *models.File
file, err = app.Server.Database.GetUserFile(uploadNewFile.Name, userSession.UserID.String())
allowedFileTypes := []string{"jpg", "jpeg", "png", "gif", "bmp", "tiff", "pdf", "doc", "docx", "txt", "odt", "xls", "xlsx", "ppt", "pptx", "zip", "rar", "tar", "gz", "7z", "bz2", "exe", "bin", "sh", "bat", "cmd", "msi", "apk"}
isAllowedFileType := func(fileType string) bool {
for _, allowed := range allowedFileTypes {
if fileType == allowed {
return true
}
}
return false
}
fileName := strings.Split(uploadNewFile.Name, ".")
fileType := fileName[len(fileName)-1]
if !isAllowedFileType(fileType) {
fileType = "doc"
}
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
fileID := uuid.New()
newFile := models.File{
ID: fileID,
OwnerID: userSession.UserID,
Name: uploadNewFile.Name,
Size: uploadNewFile.Size,
StartHash: uploadNewFile.StartHash,
EndHash: uploadNewFile.EndHash,
Type: fileType,
TotalChunk: uploadNewFile.Chunk,
Downloaded: 0,
}
err := app.Server.Database.CreateFile(&newFile)
if err != nil {
app.Server.Logger.Error(err.Error())
sendErrorResponse(conn, action.Action, "Error Creating File")
continue
}
err = app.Server.Service.RemoveUserFilesCache(context.Background(), userSession.UserID)
if err != nil {
app.Server.Logger.Error(err.Error())
sendErrorResponse(conn, action.Action, "Error Creating File")
return
}
userFile, err := app.Server.Service.GetFileDetail(context.Background(), fileID)
if err != nil {
app.Server.Logger.Error(err.Error())
sendErrorResponse(conn, action.Action, "Unknown error")
continue
}
sendSuccessResponseWithID(conn, action.Action, userFile, uploadNewFile.RequestID)
continue
} else {
app.Server.Logger.Error(err.Error())
sendErrorResponse(conn, action.Action, "Unknown error")
continue
}
}
if uploadNewFile.StartHash != file.StartHash || uploadNewFile.EndHash != file.EndHash {
sendErrorResponse(conn, action.Action, "File Is Different")
continue
}
userFile, err := app.Server.Service.GetFileDetail(context.Background(), file.ID)
if err != nil {
app.Server.Logger.Error(err.Error())
sendErrorResponse(conn, action.Action, "Unknown error")
continue
}
sendSuccessResponseWithID(conn, action.Action, userFile, uploadNewFile.RequestID)
continue
case Ping:
sendSuccessResponse(conn, action.Action, map[string]string{"message": "received"})
continue
}
}
}
func sendErrorResponse(conn *websocket.Conn, action ActionType, message string) {
response := map[string]interface{}{
"action": action,
"status": "error",
"message": message,
}
marshal, err := json.Marshal(response)
if err != nil {
app.Server.Logger.Error("Error marshalling error response:", err)
return
}
err = conn.WriteMessage(websocket.TextMessage, marshal)
if err != nil {
app.Server.Logger.Error("Error writing error response:", err)
}
}
func sendSuccessResponse(conn *websocket.Conn, action ActionType, response interface{}) {
responseJSON := map[string]interface{}{
"action": action,
"status": "success",
"response": response,
}
marshal, err := json.Marshal(responseJSON)
if err != nil {
app.Server.Logger.Error("Error marshalling success response:", err)
return
}
err = conn.WriteMessage(websocket.TextMessage, marshal)
if err != nil {
app.Server.Logger.Error("Error writing success response:", err)
}
}
func sendSuccessResponseWithID(conn *websocket.Conn, action ActionType, response interface{}, responseID string) {
responseJSON := map[string]interface{}{
"action": action,
"status": "success",
"response": response,
"responseID": responseID,
}
marshal, err := json.Marshal(responseJSON)
if err != nil {
app.Server.Logger.Error("Error marshalling success response:", err)
return
}
err = conn.WriteMessage(websocket.TextMessage, marshal)
if err != nil {
app.Server.Logger.Error("Error writing success response:", err)
}
}

View File

@ -0,0 +1,221 @@
package websocketHandler
import (
"context"
"encoding/json"
"errors"
"github.com/fossyy/filekeeper/app"
"github.com/fossyy/filekeeper/types"
"github.com/fossyy/filekeeper/types/models"
"github.com/google/uuid"
"github.com/gorilla/websocket"
"gorm.io/gorm"
"net/http"
"strings"
)
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
}
type ActionUploadNewFile struct {
Action string `json:"action"`
Name string `json:"name"`
Size uint64 `json:"size"`
Chunk uint64 `json:"chunk"`
StartHash string `json:"startHash"`
EndHash string `json:"endHash"`
RequestID string `json:"requestID"`
}
type ActionType string
type WebsocketAction struct {
Action ActionType `json:"action"`
}
const (
UploadNewFile ActionType = "UploadNewFile"
DeleteFile ActionType = "DeleteFile"
Ping ActionType = "Ping"
)
func GET(w http.ResponseWriter, r *http.Request) {
userSession := r.Context().Value("user").(types.User)
if r.Header.Get("upgrade") == "websocket" {
upgrade, err := upgrader.Upgrade(w, r, nil)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
handlerWS(upgrade, userSession)
}
}
func handlerWS(conn *websocket.Conn, userSession types.User) {
defer conn.Close()
var err error
var message []byte
for {
_, message, err = conn.ReadMessage()
if err != nil {
if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
app.Server.Logger.Error("Unexpected connection closure:", err)
} else {
app.Server.Logger.Error("Connection closed:", err)
}
return
}
var action WebsocketAction
err = json.Unmarshal(message, &action)
if err != nil {
app.Server.Logger.Error("Error unmarshalling WebsocketAction:", err)
sendErrorResponse(conn, action.Action, "Internal Server Error")
continue
}
switch action.Action {
case UploadNewFile:
var uploadNewFile ActionUploadNewFile
err = json.Unmarshal(message, &uploadNewFile)
if err != nil {
app.Server.Logger.Error("Error unmarshalling ActionUploadNewFile:", err)
sendErrorResponse(conn, action.Action, "Internal Server Error")
continue
}
var file *models.File
file, err = app.Server.Database.GetUserFile(uploadNewFile.Name, userSession.UserID.String())
allowedFileTypes := []string{"jpg", "jpeg", "png", "gif", "bmp", "tiff", "pdf", "doc", "docx", "txt", "odt", "xls", "xlsx", "ppt", "pptx", "zip", "rar", "tar", "gz", "7z", "bz2", "exe", "bin", "sh", "bat", "cmd", "msi", "apk"}
isAllowedFileType := func(fileType string) bool {
for _, allowed := range allowedFileTypes {
if fileType == allowed {
return true
}
}
return false
}
fileName := strings.Split(uploadNewFile.Name, ".")
fileType := fileName[len(fileName)-1]
if !isAllowedFileType(fileType) {
fileType = "doc"
}
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
fileID := uuid.New()
newFile := models.File{
ID: fileID,
OwnerID: userSession.UserID,
Name: uploadNewFile.Name,
Size: uploadNewFile.Size,
StartHash: uploadNewFile.StartHash,
EndHash: uploadNewFile.EndHash,
Type: fileType,
TotalChunk: uploadNewFile.Chunk,
Downloaded: 0,
}
err := app.Server.Database.CreateFile(&newFile)
if err != nil {
app.Server.Logger.Error(err.Error())
sendErrorResponse(conn, action.Action, "Error Creating File")
continue
}
err = app.Server.Service.RemoveUserFilesCache(context.Background(), userSession.UserID)
if err != nil {
app.Server.Logger.Error(err.Error())
sendErrorResponse(conn, action.Action, "Error Creating File")
return
}
userFile, err := app.Server.Service.GetFileDetail(context.Background(), fileID)
if err != nil {
app.Server.Logger.Error(err.Error())
sendErrorResponse(conn, action.Action, "Unknown error")
continue
}
sendSuccessResponseWithID(conn, action.Action, userFile, uploadNewFile.RequestID)
continue
} else {
app.Server.Logger.Error(err.Error())
sendErrorResponse(conn, action.Action, "Unknown error")
continue
}
}
if uploadNewFile.StartHash != file.StartHash || uploadNewFile.EndHash != file.EndHash {
sendErrorResponse(conn, action.Action, "File Is Different")
continue
}
userFile, err := app.Server.Service.GetFileDetail(context.Background(), file.ID)
if err != nil {
app.Server.Logger.Error(err.Error())
sendErrorResponse(conn, action.Action, "Unknown error")
continue
}
sendSuccessResponseWithID(conn, action.Action, userFile, uploadNewFile.RequestID)
continue
case Ping:
sendSuccessResponse(conn, action.Action, map[string]string{"message": "received"})
continue
}
}
}
func sendErrorResponse(conn *websocket.Conn, action ActionType, message string) {
response := map[string]interface{}{
"action": action,
"status": "error",
"message": message,
}
marshal, err := json.Marshal(response)
if err != nil {
app.Server.Logger.Error("Error marshalling error response:", err)
return
}
err = conn.WriteMessage(websocket.TextMessage, marshal)
if err != nil {
app.Server.Logger.Error("Error writing error response:", err)
}
}
func sendSuccessResponse(conn *websocket.Conn, action ActionType, response interface{}) {
responseJSON := map[string]interface{}{
"action": action,
"status": "success",
"response": response,
}
marshal, err := json.Marshal(responseJSON)
if err != nil {
app.Server.Logger.Error("Error marshalling success response:", err)
return
}
err = conn.WriteMessage(websocket.TextMessage, marshal)
if err != nil {
app.Server.Logger.Error("Error writing success response:", err)
}
}
func sendSuccessResponseWithID(conn *websocket.Conn, action ActionType, response interface{}, responseID string) {
responseJSON := map[string]interface{}{
"action": action,
"status": "success",
"response": response,
"responseID": responseID,
}
marshal, err := json.Marshal(responseJSON)
if err != nil {
app.Server.Logger.Error("Error marshalling success response:", err)
return
}
err = conn.WriteMessage(websocket.TextMessage, marshal)
if err != nil {
app.Server.Logger.Error("Error writing success response:", err)
}
}

View File

@ -109,7 +109,7 @@ func Auth(next http.HandlerFunc) http.Handler {
Path: "/",
})
}
http.Redirect(w, r, "/signin", http.StatusSeeOther)
http.Redirect(w, r, "/auth/signin", http.StatusSeeOther)
return
case session.InvalidSession:
http.SetCookie(w, &http.Cookie{
@ -118,7 +118,7 @@ func Auth(next http.HandlerFunc) http.Handler {
Path: "/",
MaxAge: -1,
})
http.Redirect(w, r, "/signin", http.StatusSeeOther)
http.Redirect(w, r, "/auth/signin", http.StatusSeeOther)
return
case session.Suspicious:
userSession := session.Get(sessionID)
@ -137,7 +137,7 @@ func Auth(next http.HandlerFunc) http.Handler {
Path: "/",
MaxAge: -1,
})
http.Redirect(w, r, "/signin?error=suspicious_session", http.StatusSeeOther)
http.Redirect(w, r, "/auth/signin?error=suspicious_session", http.StatusSeeOther)
return
default:
http.Redirect(w, r, "/", http.StatusSeeOther)

View File

@ -1,6 +1,6 @@
if (!window.mySocket) {
const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
window.mySocket = new WebSocket(`${wsProtocol}//${window.location.host}/user`);
window.mySocket = new WebSocket(`${wsProtocol}//${window.location.host}/ws`);
window.mySocket.onopen = function(event) {
console.log('WebSocket is open now.');

View File

@ -3,6 +3,7 @@ var isValid = false;
var hasUppercase = false;
function validatePasswords() {
var checkContainer = document.getElementById('checkContainer')
var password = document.getElementById('password').value;
var confirmPassword = document.getElementById('confirmPassword').value;
var matchGoodPath = document.getElementById('matchGoodPath');
@ -17,7 +18,12 @@ function validatePasswords() {
var matchStatusText = document.getElementById('matchStatusText');
var lengthStatusText = document.getElementById('lengthStatusText');
var uppercaseStatusText = document.getElementById('uppercaseStatusText');
console.log("jalan")
if (password.length > 0) {
checkContainer.classList.remove("hidden")
} else {
checkContainer.classList.add("hidden")
}
if (password === confirmPassword && password.length > 0 && confirmPassword.length > 0 && password.length === confirmPassword.length) {
matchSvgContainer.classList.remove('bg-red-200');
matchSvgContainer.classList.add('bg-green-200');

View File

@ -1,9 +1,14 @@
package client
import (
"github.com/fossyy/filekeeper/handler/auth/forgotPassword"
"github.com/fossyy/filekeeper/handler/auth/forgotPassword/verify"
googleOauthHandler "github.com/fossyy/filekeeper/handler/auth/google"
googleOauthCallbackHandler "github.com/fossyy/filekeeper/handler/auth/google/callback"
googleOauthSetupHandler "github.com/fossyy/filekeeper/handler/auth/google/setup"
"github.com/fossyy/filekeeper/handler/auth/signin"
"github.com/fossyy/filekeeper/handler/auth/signup"
"github.com/fossyy/filekeeper/handler/auth/signup/verify"
totpHandler "github.com/fossyy/filekeeper/handler/auth/totp"
fileHandler "github.com/fossyy/filekeeper/handler/file"
deleteHandler "github.com/fossyy/filekeeper/handler/file/delete"
@ -13,62 +18,59 @@ import (
fileTableHandler "github.com/fossyy/filekeeper/handler/file/table"
uploadHandler "github.com/fossyy/filekeeper/handler/file/upload"
visibilityHandler "github.com/fossyy/filekeeper/handler/file/visibility"
forgotPasswordHandler "github.com/fossyy/filekeeper/handler/forgotPassword"
forgotPasswordVerifyHandler "github.com/fossyy/filekeeper/handler/forgotPassword/verify"
indexHandler "github.com/fossyy/filekeeper/handler/index"
logoutHandler "github.com/fossyy/filekeeper/handler/logout"
signinHandler "github.com/fossyy/filekeeper/handler/signin"
signupHandler "github.com/fossyy/filekeeper/handler/signup"
signupVerifyHandler "github.com/fossyy/filekeeper/handler/signup/verify"
userHandler "github.com/fossyy/filekeeper/handler/user"
userHandlerResetPassword "github.com/fossyy/filekeeper/handler/user/ResetPassword"
userSessionTerminateHandler "github.com/fossyy/filekeeper/handler/user/session/terminate"
userHandlerTotpSetup "github.com/fossyy/filekeeper/handler/user/totp"
websocketHandler "github.com/fossyy/filekeeper/handler/websocket"
"github.com/fossyy/filekeeper/middleware"
"net/http"
)
func SetupRoutes() *http.ServeMux {
handler := http.NewServeMux()
// Index
handler.HandleFunc("GET /{$}", indexHandler.GET)
// Auth Routes
handler.Handle("GET /auth/google", middleware.Guest(googleOauthHandler.GET))
handler.Handle("GET /auth/totp", middleware.Guest(totpHandler.GET))
handler.Handle("POST /auth/totp", middleware.Guest(totpHandler.POST))
handler.Handle("GET /auth/google/callback", middleware.Guest(googleOauthCallbackHandler.GET))
handler.Handle("GET /auth/google/setup/{code}", middleware.Guest(googleOauthSetupHandler.GET))
handler.Handle("POST /auth/google/setup/{code}", middleware.Guest(googleOauthSetupHandler.POST))
authRoute := http.NewServeMux()
handler.Handle("/auth/", http.StripPrefix("/auth", authRoute))
authRoute.Handle("GET /google", middleware.Guest(googleOauthHandler.GET))
authRoute.Handle("GET /totp", middleware.Guest(totpHandler.GET))
authRoute.Handle("POST /totp", middleware.Guest(totpHandler.POST))
authRoute.Handle("GET /google/callback", middleware.Guest(googleOauthCallbackHandler.GET))
authRoute.Handle("GET /google/setup/{code}", middleware.Guest(googleOauthSetupHandler.GET))
authRoute.Handle("POST /google/setup/{code}", middleware.Guest(googleOauthSetupHandler.POST))
authRoute.Handle("GET /signin", middleware.Guest(signinHandler.GET))
authRoute.Handle("POST /signin", middleware.Guest(signinHandler.POST))
authRoute.Handle("GET /signup", middleware.Guest(signupHandler.GET))
authRoute.Handle("POST /signup", middleware.Guest(signupHandler.POST))
authRoute.Handle("GET /signup/verify/{code}", middleware.Guest(signupVerifyHandler.GET))
authRoute.Handle("GET /forgot-password", middleware.Guest(forgotPasswordHandler.GET))
authRoute.Handle("POST /forgot-password", middleware.Guest(forgotPasswordHandler.POST))
authRoute.Handle("GET /forgot-password/verify/{code}", middleware.Guest(forgotPasswordVerifyHandler.GET))
authRoute.Handle("POST /forgot-password/verify/{code}", middleware.Guest(forgotPasswordVerifyHandler.POST))
// Signin/Signup/Forgot Password
handler.Handle("GET /signin", middleware.Guest(signinHandler.GET))
handler.Handle("POST /signin", middleware.Guest(signinHandler.POST))
handler.Handle("GET /signup", middleware.Guest(signupHandler.GET))
handler.Handle("POST /signup", middleware.Guest(signupHandler.POST))
handler.Handle("GET /signup/verify/{code}", middleware.Guest(signupVerifyHandler.GET))
handler.Handle("GET /forgot-password", middleware.Guest(forgotPasswordHandler.GET))
handler.Handle("POST /forgot-password", middleware.Guest(forgotPasswordHandler.POST))
handler.Handle("GET /forgot-password/verify/{code}", middleware.Guest(forgotPasswordVerifyHandler.GET))
handler.Handle("POST /forgot-password/verify/{code}", middleware.Guest(forgotPasswordVerifyHandler.POST))
userRoute := http.NewServeMux()
handler.Handle("/user/", http.StripPrefix("/user", userRoute))
userRoute.Handle("GET /{$}", middleware.Auth(userHandler.GET))
userRoute.Handle("POST /reset-password", middleware.Auth(userHandlerResetPassword.POST))
userRoute.Handle("DELETE /session/terminate/{id}", middleware.Auth(userSessionTerminateHandler.DELETE))
userRoute.Handle("GET /totp/setup", middleware.Auth(userHandlerTotpSetup.GET))
userRoute.Handle("POST /totp/setup", middleware.Auth(userHandlerTotpSetup.POST))
// User Routes
handler.Handle("GET /user", middleware.Auth(userHandler.GET))
handler.Handle("POST /user/reset-password", middleware.Auth(userHandlerResetPassword.POST))
handler.Handle("DELETE /user/session/terminate/{id}", middleware.Auth(userSessionTerminateHandler.DELETE))
handler.Handle("GET /user/totp/setup", middleware.Auth(userHandlerTotpSetup.GET))
handler.Handle("POST /user/totp/setup", middleware.Auth(userHandlerTotpSetup.POST))
handler.Handle("/ws", middleware.Auth(websocketHandler.GET))
// File Routes
handler.Handle("GET /file", middleware.Auth(fileHandler.GET))
handler.Handle("GET /file/table", middleware.Auth(fileTableHandler.GET))
handler.Handle("GET /file/query", middleware.Auth(queryHandler.GET))
handler.Handle("POST /file/{id}", middleware.Auth(uploadHandler.POST))
handler.Handle("DELETE /file/{id}", middleware.Auth(deleteHandler.DELETE))
handler.HandleFunc("GET /file/{id}", downloadHandler.GET)
handler.Handle("PUT /file/{id}", middleware.Auth(visibilityHandler.PUT))
handler.Handle("PATCH /file/{id}", middleware.Auth(renameFileHandler.PATCH))
fileRoute := http.NewServeMux()
handler.Handle("/file/", http.StripPrefix("/file", fileRoute))
fileRoute.Handle("GET /{$}", middleware.Auth(fileHandler.GET))
fileRoute.Handle("GET /table", middleware.Auth(fileTableHandler.GET))
fileRoute.Handle("GET /query", middleware.Auth(queryHandler.GET))
fileRoute.Handle("POST /{id}", middleware.Auth(uploadHandler.POST))
fileRoute.Handle("DELETE /{id}", middleware.Auth(deleteHandler.DELETE))
fileRoute.HandleFunc("GET /{id}", downloadHandler.GET)
fileRoute.Handle("PUT /{id}", middleware.Auth(visibilityHandler.PUT))
fileRoute.Handle("PATCH /{id}", middleware.Auth(renameFileHandler.PATCH))
handler.Handle("GET /logout", middleware.Auth(logoutHandler.GET))

4
staging.sh Normal file → Executable file
View File

@ -1,5 +1,5 @@
#!/bin/bash
air &
npx tailwindcss -i ./public/input.css -o ./public/output.css --watch &
templ generate -watch -proxy=http://localhost:8000
templ generate -watch &
npx tailwindcss -i ./public/input.css -o ./public/output.css --watch

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.2.778
// templ: version: v0.2.786
package layout
//lint:file-ignore SA4006 This context is only used if a nested component is present.
@ -29,7 +29,7 @@ func Base() templ.Component {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 1)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<!doctype html><html lang=\"en\"><head><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><link href=\"/public/output.css\" rel=\"stylesheet\"><title>Admin Page</title><script src=\"https://unpkg.com/htmx.org@1.9.12\"></script></head><body><div id=\"content\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -37,7 +37,7 @@ func Base() templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 2)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></body></html>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}

View File

@ -7,38 +7,27 @@ import (
templ form(err types.Message, title string) {
@layout.Base(title){
<div class="dark flex items-center min-h-screen p-4 sm:p-6 bg-gray-900">
<div class="mx-auto w-full max-w-md space-y-8">
<header class="text-center">
<div class="space-y-2">
<h1 class="text-3xl font-bold text-white">Set Up Your Account</h1>
<p class="text-gray-500 dark:text-gray-400">Enter your information to create a new account</p>
switch err.Code {
case 0:
<div class="p-4 mb-4 text-sm text-red-800 rounded-lg bg-red-50 dark:bg-gray-800 dark:text-red-400" role="alert">
{err.Message}
</div>
case 1:
<div class="p-4 mb-4 text-sm text-green-800 rounded-lg bg-green-50 dark:bg-gray-800 dark:text-green-400" role="alert">
{err.Message}
</div>
}
<div class="bg-gray-100 flex items-center justify-center min-h-screen">
<div class="bg-white p-8 rounded-lg shadow-md w-full max-w-md">
<h1 class="text-2xl font-bold mb-6 text-center text-gray-800">Sign Up</h1>
<form action="" method="POST" class="space-y-4">
<div>
<label for="username" class="block text-sm font-medium text-gray-700">Username</label>
<input type="text" id="username" name="username" required
class="mt-1 block w-full px-3 py-2 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500">
</div>
</header>
<form class="space-y-4" method="post" action="">
<div class="space-y-2">
<label class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 text-white" for="username">Username</label>
<input type="text" class="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:bg-gray-800 dark:text-white" id="username" name="username" required="" />
<div>
<label for="password" class="block text-sm font-medium text-gray-700">Password</label>
<input type="password" id="password" name="password" required
class="mt-1 block w-full px-3 py-2 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500">
</div>
<div class="space-y-2">
<label class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 text-white" for="password">Password</label>
<input type="password" class="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:bg-gray-800 dark:text-white" id="password" name="password" required />
</div>
<div class="space-y-2">
<label class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 text-white" for="confirmPassword">Confirm Password</label>
<input type="password" class="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:bg-gray-800 dark:text-white" id="confirmPassword" required />
</div>
<div class="flex justify-start mt-3 ml-4 p-1">
<div>
<label for="confirmPassword" class="block text-sm font-medium text-gray-700">Confirm Password</label>
<input type="password" id="confirmPassword" name="confirmPassword" required
class="mt-1 block w-full px-3 py-2 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500">
</div>
<div>
<div id="checkContainer" class="flex justify-start mt-1 block w-full px-3 py-2 hidden">
<ul>
<li class="flex items-center py-1">
<div id="matchSvgContainer" class="rounded-full p-1 fill-current bg-red-200 text-green-700">
@ -69,19 +58,26 @@ templ form(err types.Message, title string) {
</li>
</ul>
</div>
<button class="bg-slate-200 inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-10 px-4 py-2 w-full" type="submit" id="submit" name="submit" disabled>
Sign up
</button>
<button id="submit"
type="submit"
disabled
class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 disabled:pointer-events-none disabled:opacity-50">
Sign Up
</button>
</div>
</form>
<div class="text-center text-sm text-white">
Already have an account?
<a class="underline" href="/signin" rel="ugc" hx-get="/signin" hx-swap="outerHTML" hx-push-url="true" hx-target="#content">
Sign in
</a>
<div class="mt-6 text-center">
<p class="text-sm text-gray-600">
Already have an account?
<a class="underline" href="/auth/signin" rel="ugc" hx-get="/auth/signin" hx-swap="outerHTML" hx-push-url="true"
hx-target="#content" class="font-medium text-indigo-600 hover:text-indigo-500">
Log in
</a>
</p>
</div>
</div>
<script src="/public/validatePassword.js" />
</div>
<script src="/public/validatePassword.js" />
}
}

View File

@ -1,6 +1,6 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.2.778
// templ: version: v0.2.786
package authView
//lint:file-ignore SA4006 This context is only used if a nested component is present.
@ -46,49 +46,7 @@ func form(err types.Message, title string) templ.Component {
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 1)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
switch err.Code {
case 0:
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 2)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(err.Message)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/client/auth/auth.templ`, Line: 19, Col: 38}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 3)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
case 1:
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 4)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(err.Message)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/client/auth/auth.templ`, Line: 23, Col: 38}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 5)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 6)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"bg-gray-100 flex items-center justify-center min-h-screen\"><div class=\"bg-white p-8 rounded-lg shadow-md w-full max-w-md\"><h1 class=\"text-2xl font-bold mb-6 text-center text-gray-800\">Sign Up</h1><form action=\"\" method=\"POST\" class=\"space-y-4\"><div><label for=\"username\" class=\"block text-sm font-medium text-gray-700\">Username</label> <input type=\"text\" id=\"username\" name=\"username\" required class=\"mt-1 block w-full px-3 py-2 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500\"></div><div><label for=\"password\" class=\"block text-sm font-medium text-gray-700\">Password</label> <input type=\"password\" id=\"password\" name=\"password\" required class=\"mt-1 block w-full px-3 py-2 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500\"></div><div><label for=\"confirmPassword\" class=\"block text-sm font-medium text-gray-700\">Confirm Password</label> <input type=\"password\" id=\"confirmPassword\" name=\"confirmPassword\" required class=\"mt-1 block w-full px-3 py-2 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500\"></div><div><div id=\"checkContainer\" class=\"flex justify-start mt-1 block w-full px-3 py-2 hidden\"><ul><li class=\"flex items-center py-1\"><div id=\"matchSvgContainer\" class=\"rounded-full p-1 fill-current bg-red-200 text-green-700\"><svg id=\"matchSvgIcon\" class=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\"><path id=\"matchGoodPath\" style=\"display: none;\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 13l4 4L19 7\"></path> <path id=\"matchBadPath\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\"></path></svg></div><span id=\"matchStatusText\" class=\"font-medium text-sm ml-3 text-red-700\">Passwords do not match</span></li><li class=\"flex items-center py-1\"><div id=\"uppercaseSvgContainer\" class=\"rounded-full p-1 fill-current bg-red-200 text-green-700\"><svg id=\"uppercaseSvgIcon\" class=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\"><path id=\"uppercaseGoodPath\" style=\"display: none;\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 13l4 4L19 7\"></path> <path id=\"uppercaseBadPath\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\"></path></svg></div><span id=\"uppercaseStatusText\" class=\"font-medium text-sm ml-3 text-red-700\">Password must contain at least one uppercase letter</span></li><li class=\"flex items-center py-1\"><div id=\"lengthSvgContainer\" class=\"rounded-full p-1 fill-current bg-red-200 text-green-700\"><svg id=\"lengthSvgIcon\" class=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\"><path id=\"lengthGoodPath\" style=\"display: none;\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 13l4 4L19 7\"></path> <path id=\"lengthBadPath\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\"></path></svg></div><span id=\"lengthStatusText\" class=\"font-medium text-sm ml-3 text-red-700\">Password length must be at least 8 characters</span></li></ul></div><button id=\"submit\" type=\"submit\" disabled class=\"w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 disabled:pointer-events-none disabled:opacity-50\">Sign Up</button></div></form><div class=\"mt-6 text-center\"><p class=\"text-sm text-gray-600\">Already have an account? <a class=\"underline\" href=\"/auth/signin\" rel=\"ugc\" hx-get=\"/auth/signin\" hx-swap=\"outerHTML\" hx-push-url=\"true\" hx-target=\"#content\" class=\"font-medium text-indigo-600 hover:text-indigo-500\">Log in</a></p></div></div><script src=\"/public/validatePassword.js\"></script></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -118,9 +76,9 @@ func GoogleSetup(title string, err types.Message) templ.Component {
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var5 := templ.GetChildren(ctx)
if templ_7745c5c3_Var5 == nil {
templ_7745c5c3_Var5 = templ.NopComponent
templ_7745c5c3_Var3 := templ.GetChildren(ctx)
if templ_7745c5c3_Var3 == nil {
templ_7745c5c3_Var3 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = form(err, title).Render(ctx, templ_7745c5c3_Buffer)

View File

@ -7,30 +7,43 @@ import (
templ content(title string, err types.Message) {
@layout.Base(title){
<div class="dark flex items-center min-h-screen p-4 sm:p-6 bg-gray-900">
<div class="mx-auto w-full max-w-md space-y-8">
<header class="text-center">
<div class="space-y-2">
<h1 class="text-3xl font-bold text-white">Forgot password</h1>
<p class="text-gray-500 dark:text-gray-400">Enter your email below to reset your password</p>
switch err.Code {
case 0:
<div class="p-4 mb-4 text-sm text-red-800 rounded-lg bg-red-50 dark:bg-gray-800 dark:text-red-400" role="alert">
{err.Message}
</div>
}
</div>
</header>
<form class="space-y-4" method="post" action="">
<div class="space-y-2">
<label class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 text-white" for="email">Email</label>
<input type="email" class="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:bg-gray-800 dark:text-white" id="email" name="email" placeholder="m@example.com" required="" />
</div>
<button class="bg-slate-200 inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-10 px-4 py-2 w-full" type="submit">
Submit
</button>
</form>
</div>
<div class="bg-gray-100 flex items-center justify-center min-h-screen">
<div class="bg-white p-8 rounded-lg shadow-md w-full max-w-md">
<h1 class="text-2xl font-bold mb-6 text-center text-gray-800">Forgot Password</h1>
<p class="text-gray-600 text-sm mb-6 text-center">Enter your email address and we'll send you instructions to reset your password.</p>
<form action="#" method="POST" class="space-y-4">
switch err.Code {
case 0:
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative mb-4" role="alert">
<strong class="font-bold">Error!</strong>
<span class="block sm:inline"> {err.Message} </span>
</div>
}
<div>
<label for="email" class="block text-sm font-medium text-gray-700">Email</label>
<input type="email" id="email" name="email" required
class="mt-1 block w-full px-3 py-2 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500">
</div>
<div>
<button type="submit"
class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
Send Reset Instructions
</button>
</div>
</form>
<div class="mt-6 flex items-center justify-between">
<div class="text-sm">
<a href="/auth/signin" rel="ugc" hx-get="/auth/signin" hx-swap="outerHTML" hx-push-url="true" hx-target="#content" class="font-medium text-indigo-600 hover:text-indigo-500">
Return to Login
</a>
</div>
<div class="text-sm">
<a href="/auth/signup" rel="ugc" hx-get="/auth/signup" hx-swap="outerHTML" hx-push-url="true" hx-target="#content" class="font-medium text-indigo-600 hover:text-indigo-500">
Create an account
</a>
</div>
</div>
</div>
</div>
}
}

View File

@ -1,6 +1,6 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.2.778
// templ: version: v0.2.786
package forgotPasswordView
//lint:file-ignore SA4006 This context is only used if a nested component is present.
@ -46,31 +46,31 @@ func content(title string, err types.Message) templ.Component {
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 1)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"bg-gray-100 flex items-center justify-center min-h-screen\"><div class=\"bg-white p-8 rounded-lg shadow-md w-full max-w-md\"><h1 class=\"text-2xl font-bold mb-6 text-center text-gray-800\">Forgot Password</h1><p class=\"text-gray-600 text-sm mb-6 text-center\">Enter your email address and we'll send you instructions to reset your password.</p><form action=\"#\" method=\"POST\" class=\"space-y-4\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
switch err.Code {
case 0:
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 2)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative mb-4\" role=\"alert\"><strong class=\"font-bold\">Error!</strong> <span class=\"block sm:inline\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(err.Message)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/client/forgotPassword/forgotPassword.templ`, Line: 19, Col: 38}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/client/auth/forgotPassword/forgotPassword.templ`, Line: 19, Col: 75}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 3)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</span></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 4)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div><label for=\"email\" class=\"block text-sm font-medium text-gray-700\">Email</label> <input type=\"email\" id=\"email\" name=\"email\" required class=\"mt-1 block w-full px-3 py-2 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500\"></div><div><button type=\"submit\" class=\"w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500\">Send Reset Instructions</button></div></form><div class=\"mt-6 flex items-center justify-between\"><div class=\"text-sm\"><a href=\"/auth/signin\" rel=\"ugc\" hx-get=\"/auth/signin\" hx-swap=\"outerHTML\" hx-push-url=\"true\" hx-target=\"#content\" class=\"font-medium text-indigo-600 hover:text-indigo-500\">Return to Login</a></div><div class=\"text-sm\"><a href=\"/auth/signup\" rel=\"ugc\" hx-get=\"/auth/signup\" hx-swap=\"outerHTML\" hx-push-url=\"true\" hx-target=\"#content\" class=\"font-medium text-indigo-600 hover:text-indigo-500\">Create an account</a></div></div></div></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -146,31 +146,31 @@ func NewPasswordForm(title string, err types.Message) templ.Component {
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 5)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"dark flex items-center min-h-screen p-4 sm:p-6 bg-gray-900\"><div class=\"mx-auto w-full max-w-md space-y-8\"><header class=\"text-center\"><div class=\"space-y-2\"><h1 class=\"text-3xl font-bold text-white\">Forgot password</h1><p class=\"text-gray-500 dark:text-gray-400\">Enter your email below to reset your password</p>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
switch err.Code {
case 0:
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 6)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"p-4 mb-4 text-sm text-red-800 rounded-lg bg-red-50 dark:bg-gray-800 dark:text-red-400\" role=\"alert\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(err.Message)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/client/forgotPassword/forgotPassword.templ`, Line: 53, Col: 38}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/client/auth/forgotPassword/forgotPassword.templ`, Line: 66, Col: 38}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 7)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 8)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></header><form class=\"space-y-4\" method=\"post\" action=\"\"><div class=\"space-y-2\"><label class=\"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 text-white\" for=\"password\">Password</label> <input type=\"password\" class=\"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:bg-gray-800 dark:text-white\" id=\"password\" name=\"password\" required></div><div class=\"space-y-2\"><label class=\"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 text-white\" for=\"confirmPassword\">Confirm Password</label> <input type=\"password\" class=\"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:bg-gray-800 dark:text-white\" id=\"confirmPassword\" required></div><div class=\"flex justify-start mt-3 ml-4 p-1\"><ul><li class=\"flex items-center py-1\"><div id=\"matchSvgContainer\" class=\"rounded-full p-1 fill-current bg-red-200 text-green-700\"><svg id=\"matchSvgIcon\" class=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\"><path id=\"matchGoodPath\" style=\"display: none;\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 13l4 4L19 7\"></path> <path id=\"matchBadPath\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\"></path></svg></div><span id=\"matchStatusText\" class=\"font-medium text-sm ml-3 text-red-700\">Passwords do not match</span></li><li class=\"flex items-center py-1\"><div id=\"uppercaseSvgContainer\" class=\"rounded-full p-1 fill-current bg-red-200 text-green-700\"><svg id=\"uppercaseSvgIcon\" class=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\"><path id=\"uppercaseGoodPath\" style=\"display: none;\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 13l4 4L19 7\"></path> <path id=\"uppercaseBadPath\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\"></path></svg></div><span id=\"uppercaseStatusText\" class=\"font-medium text-sm ml-3 text-red-700\">Password must contain at least one uppercase letter</span></li><li class=\"flex items-center py-1\"><div id=\"lengthSvgContainer\" class=\"rounded-full p-1 fill-current bg-red-200 text-green-700\"><svg id=\"lengthSvgIcon\" class=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\"><path id=\"lengthGoodPath\" style=\"display: none;\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 13l4 4L19 7\"></path> <path id=\"lengthBadPath\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\"></path></svg></div><span id=\"lengthStatusText\" class=\"font-medium text-sm ml-3 text-red-700\">Password length must be at least 8 characters</span></li></ul></div><button class=\"bg-slate-200 inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-10 px-4 py-2 w-full\" type=\"submit\" id=\"submit\" name=\"submit\" disabled>Submit</button></form></div></div><script src=\"/public/validatePassword.js\"></script>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -217,7 +217,7 @@ func EmailSend(title string) templ.Component {
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 9)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<style>h1, h2, h3, h4, h5, h6 { font-family: 'Arimo', sans-serif; --font-sans: 'Arimo'; }</style> <style>body { font-family: 'Libre Franklin', sans-serif; --font-sans: 'Libre Franklin'; }</style> <div class=\"flex flex-col items-center justify-center min-h-[80vh] gap-6\"><div class=\"flex items-center justify-center\"><svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"h-16 w-16 text-gray-500 dark:text-gray-400\"><rect width=\"20\" height=\"16\" x=\"2\" y=\"4\" rx=\"2\"></rect> <path d=\"m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7\"></path></svg></div><div class=\"space-y-2 text-center\"><h1 class=\"text-3xl font-bold\">Email Verification Sent</h1><p class=\"text-gray-500 dark:text-gray-400\">We've sent a verification email to your inbox. Please check your email and follow the instructions to change your password.</p></div></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -264,7 +264,7 @@ func ChangeSuccess(title string) templ.Component {
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 10)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<style>h1, h2, h3, h4, h5, h6 { font-family: 'Arimo', sans-serif; --font-sans: 'Arimo'; }</style> <style>body { font-family: 'Libre Franklin', sans-serif; --font-sans: 'Libre Franklin'; }</style> <div class=\"flex flex-col items-center justify-center min-h-[80vh] gap-6\"><div class=\"bg-green-500 text-white rounded-full p-4\"><svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"h-8 w-8\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg></div><div class=\"space-y-2 text-center\"><h1 class=\"text-3xl font-bold\">Password Changed Successfully</h1><p class=\"text-gray-500 dark:text-gray-400\">Your password has been successfully updated. Feel free to continue enjoying our platform.</p></div></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}

View File

@ -0,0 +1,88 @@
package signinView
import (
"github.com/fossyy/filekeeper/types"
"github.com/fossyy/filekeeper/view/client/layout"
)
templ content(err types.Message, title string) {
@layout.Base(title){
<div class="bg-gray-100 flex items-center justify-center min-h-screen">
<div class="bg-white p-8 rounded-lg shadow-md w-full max-w-md">
<h1 class="text-2xl font-bold mb-6 text-center text-gray-800">Login</h1>
switch err.Code {
case 0:
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative mb-4" role="alert">
<strong class="font-bold">Error!</strong>
<span class="block sm:inline"> {err.Message} </span>
</div>
}
<form action="" method="POST" class="space-y-4">
<div>
<label for="email" class="block text-sm font-medium text-gray-700">Email</label>
<input type="email" id="email" name="email" required
class="mt-1 block w-full px-3 py-2 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500">
</div>
<div>
<label for="password" class="block text-sm font-medium text-gray-700">Password</label>
<input type="password" id="password" name="password" required
class="mt-1 block w-full px-3 py-2 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500">
</div>
<div class="flex items-center justify-end">
<div class="text-sm">
<a href="/auth/forgot-password" rel="ugc" hx-get="/auth/forgot-password" hx-swap="outerHTML" hx-push-url="true" hx-target="#content" class="font-medium text-indigo-600 hover:text-indigo-500">
Forgot your password?
</a>
</div>
</div>
<div>
<button type="submit"
class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
Sign in
</button>
</div>
</form>
<div class="mt-6">
<div class="relative">
<div class="absolute inset-0 flex items-center">
<div class="w-full border-t border-gray-300"></div>
</div>
<div class="relative flex justify-center text-sm">
<span class="px-2 bg-white text-gray-500">Or continue with</span>
</div>
</div>
<div class="mt-6">
<a href="/auth/google"
class="w-full flex items-center justify-center px-4 py-2 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
<svg class="h-5 w-5 mr-2" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<g transform="matrix(1, 0, 0, 1, 27.009001, -39.238998)">
<path fill="#4285F4"
d="M -3.264 51.509 C -3.264 50.719 -3.334 49.969 -3.454 49.239 L -14.754 49.239 L -14.754 53.749 L -8.284 53.749 C -8.574 55.229 -9.424 56.479 -10.684 57.329 L -10.684 60.329 L -6.824 60.329 C -4.564 58.239 -3.264 55.159 -3.264 51.509 Z" />
<path fill="#34A853"
d="M -14.754 63.239 C -11.514 63.239 -8.804 62.159 -6.824 60.329 L -10.684 57.329 C -11.764 58.049 -13.134 58.489 -14.754 58.489 C -17.884 58.489 -20.534 56.379 -21.484 53.529 L -25.464 53.529 L -25.464 56.619 C -23.494 60.539 -19.444 63.239 -14.754 63.239 Z" />
<path fill="#FBBC05"
d="M -21.484 53.529 C -21.734 52.809 -21.864 52.039 -21.864 51.239 C -21.864 50.439 -21.724 49.669 -21.484 48.949 L -21.484 45.859 L -25.464 45.859 C -26.284 47.479 -26.754 49.299 -26.754 51.239 C -26.754 53.179 -26.284 54.999 -25.464 56.619 L -21.484 53.529 Z" />
<path fill="#EA4335"
d="M -14.754 43.989 C -12.984 43.989 -11.404 44.599 -10.154 45.789 L -6.734 42.369 C -8.804 40.429 -11.514 39.239 -14.754 39.239 C -19.444 39.239 -23.494 41.939 -25.464 45.859 L -21.484 48.949 C -20.534 46.099 -17.884 43.989 -14.754 43.989 Z" />
</g>
</svg>
Sign in with Google
</a>
</div>
</div>
<div class="mt-6 text-center">
<p class="text-sm text-gray-600">
Don't have an account?
<a href="/auth/signup" rel="ugc" hx-get="/auth/signup" hx-swap="outerHTML" hx-push-url="true" hx-target="#content" class="font-medium text-indigo-600 hover:text-indigo-500">
Sign up
</a>
</p>
</div>
</div>
</div>
}
}
templ Main(title string, err types.Message) {
@content(err, title)
}

View File

@ -0,0 +1,116 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.2.786
package signinView
//lint:file-ignore SA4006 This context is only used if a nested component is present.
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
import (
"github.com/fossyy/filekeeper/types"
"github.com/fossyy/filekeeper/view/client/layout"
)
func content(err types.Message, title string) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
if templ_7745c5c3_Var1 == nil {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Var2 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"bg-gray-100 flex items-center justify-center min-h-screen\"><div class=\"bg-white p-8 rounded-lg shadow-md w-full max-w-md\"><h1 class=\"text-2xl font-bold mb-6 text-center text-gray-800\">Login</h1>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
switch err.Code {
case 0:
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative mb-4\" role=\"alert\"><strong class=\"font-bold\">Error!</strong> <span class=\"block sm:inline\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(err.Message)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/client/auth/signin/signin.templ`, Line: 17, Col: 71}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</span></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<form action=\"\" method=\"POST\" class=\"space-y-4\"><div><label for=\"email\" class=\"block text-sm font-medium text-gray-700\">Email</label> <input type=\"email\" id=\"email\" name=\"email\" required class=\"mt-1 block w-full px-3 py-2 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500\"></div><div><label for=\"password\" class=\"block text-sm font-medium text-gray-700\">Password</label> <input type=\"password\" id=\"password\" name=\"password\" required class=\"mt-1 block w-full px-3 py-2 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500\"></div><div class=\"flex items-center justify-end\"><div class=\"text-sm\"><a href=\"/auth/forgot-password\" rel=\"ugc\" hx-get=\"/auth/forgot-password\" hx-swap=\"outerHTML\" hx-push-url=\"true\" hx-target=\"#content\" class=\"font-medium text-indigo-600 hover:text-indigo-500\">Forgot your password?</a></div></div><div><button type=\"submit\" class=\"w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500\">Sign in</button></div></form><div class=\"mt-6\"><div class=\"relative\"><div class=\"absolute inset-0 flex items-center\"><div class=\"w-full border-t border-gray-300\"></div></div><div class=\"relative flex justify-center text-sm\"><span class=\"px-2 bg-white text-gray-500\">Or continue with</span></div></div><div class=\"mt-6\"><a href=\"/auth/google\" class=\"w-full flex items-center justify-center px-4 py-2 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500\"><svg class=\"h-5 w-5 mr-2\" viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\"><g transform=\"matrix(1, 0, 0, 1, 27.009001, -39.238998)\"><path fill=\"#4285F4\" d=\"M -3.264 51.509 C -3.264 50.719 -3.334 49.969 -3.454 49.239 L -14.754 49.239 L -14.754 53.749 L -8.284 53.749 C -8.574 55.229 -9.424 56.479 -10.684 57.329 L -10.684 60.329 L -6.824 60.329 C -4.564 58.239 -3.264 55.159 -3.264 51.509 Z\"></path> <path fill=\"#34A853\" d=\"M -14.754 63.239 C -11.514 63.239 -8.804 62.159 -6.824 60.329 L -10.684 57.329 C -11.764 58.049 -13.134 58.489 -14.754 58.489 C -17.884 58.489 -20.534 56.379 -21.484 53.529 L -25.464 53.529 L -25.464 56.619 C -23.494 60.539 -19.444 63.239 -14.754 63.239 Z\"></path> <path fill=\"#FBBC05\" d=\"M -21.484 53.529 C -21.734 52.809 -21.864 52.039 -21.864 51.239 C -21.864 50.439 -21.724 49.669 -21.484 48.949 L -21.484 45.859 L -25.464 45.859 C -26.284 47.479 -26.754 49.299 -26.754 51.239 C -26.754 53.179 -26.284 54.999 -25.464 56.619 L -21.484 53.529 Z\"></path> <path fill=\"#EA4335\" d=\"M -14.754 43.989 C -12.984 43.989 -11.404 44.599 -10.154 45.789 L -6.734 42.369 C -8.804 40.429 -11.514 39.239 -14.754 39.239 C -19.444 39.239 -23.494 41.939 -25.464 45.859 L -21.484 48.949 C -20.534 46.099 -17.884 43.989 -14.754 43.989 Z\"></path></g></svg> Sign in with Google</a></div></div><div class=\"mt-6 text-center\"><p class=\"text-sm text-gray-600\">Don't have an account? <a href=\"/auth/signup\" rel=\"ugc\" hx-get=\"/auth/signup\" hx-swap=\"outerHTML\" hx-push-url=\"true\" hx-target=\"#content\" class=\"font-medium text-indigo-600 hover:text-indigo-500\">Sign up</a></p></div></div></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
templ_7745c5c3_Err = layout.Base(title).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
func Main(title string, err types.Message) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var4 := templ.GetChildren(ctx)
if templ_7745c5c3_Var4 == nil {
templ_7745c5c3_Var4 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = content(err, title).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
var _ = templruntime.GeneratedTemplate

View File

@ -0,0 +1,201 @@
package signup
import (
"github.com/fossyy/filekeeper/types"
"github.com/fossyy/filekeeper/view/client/layout"
)
templ form(err types.Message, title string) {
@layout.Base(title){
<div class="bg-gray-100 flex items-center justify-center min-h-screen">
<div class="bg-white p-8 rounded-lg shadow-md w-full max-w-md">
<h1 class="text-2xl font-bold mb-6 text-center text-gray-800">Sign Up</h1>
switch err.Code {
case 0:
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative mb-4" role="alert">
<strong class="font-bold">Error!</strong>
<span class="block sm:inline"> {err.Message} </span>
</div>
}
<form action="" method="POST" class="space-y-4">
<div>
<label for="email" class="block text-sm font-medium text-gray-700">Email</label>
<input type="email" id="email" name="email" required
class="mt-1 block w-full px-3 py-2 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500">
</div>
<div>
<label for="username" class="block text-sm font-medium text-gray-700">Username</label>
<input type="text" id="username" name="username" required
class="mt-1 block w-full px-3 py-2 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500">
</div>
<div>
<label for="password" class="block text-sm font-medium text-gray-700">Password</label>
<input type="password" id="password" name="password" required
class="mt-1 block w-full px-3 py-2 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500">
</div>
<div>
<label for="confirmPassword" class="block text-sm font-medium text-gray-700">Confirm Password</label>
<input type="password" id="confirmPassword" name="confirmPassword" required
class="mt-1 block w-full px-3 py-2 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500">
</div>
<div>
<div id="checkContainer" class="flex justify-start mt-1 block w-full px-3 py-2 hidden">
<ul>
<li class="flex items-center py-1">
<div id="matchSvgContainer" class="rounded-full p-1 fill-current bg-red-200 text-green-700">
<svg id="matchSvgIcon" class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path id="matchGoodPath" style="display: none;" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
<path id="matchBadPath" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
</svg>
</div>
<span id="matchStatusText" class="font-medium text-sm ml-3 text-red-700"> Passwords do not match</span>
</li>
<li class="flex items-center py-1">
<div id="uppercaseSvgContainer" class="rounded-full p-1 fill-current bg-red-200 text-green-700">
<svg id="uppercaseSvgIcon" class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path id="uppercaseGoodPath" style="display: none;" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
<path id="uppercaseBadPath" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
</svg>
</div>
<span id="uppercaseStatusText" class="font-medium text-sm ml-3 text-red-700"> Password must contain at least one uppercase letter</span>
</li>
<li class="flex items-center py-1">
<div id="lengthSvgContainer" class="rounded-full p-1 fill-current bg-red-200 text-green-700">
<svg id="lengthSvgIcon" class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path id="lengthGoodPath" style="display: none;" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
<path id="lengthBadPath" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
</svg>
</div>
<span id="lengthStatusText" class="font-medium text-sm ml-3 text-red-700"> Password length must be at least 8 characters</span>
</li>
</ul>
</div>
<button id="submit"
type="submit"
disabled
class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 disabled:pointer-events-none disabled:opacity-50">
Sign Up
</button>
</div>
</form>
<div class="mt-6">
<div class="relative">
<div class="absolute inset-0 flex items-center">
<div class="w-full border-t border-gray-300"></div>
</div>
<div class="relative flex justify-center text-sm">
<span class="px-2 bg-white text-gray-500">Or continue with</span>
</div>
</div>
<div class="mt-6">
<a href="/auth/google"
class="w-full flex items-center justify-center px-4 py-2 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
<svg class="h-5 w-5 mr-2" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<g transform="matrix(1, 0, 0, 1, 27.009001, -39.238998)">
<path fill="#4285F4"
d="M -3.264 51.509 C -3.264 50.719 -3.334 49.969 -3.454 49.239 L -14.754 49.239 L -14.754 53.749 L -8.284 53.749 C -8.574 55.229 -9.424 56.479 -10.684 57.329 L -10.684 60.329 L -6.824 60.329 C -4.564 58.239 -3.264 55.159 -3.264 51.509 Z" />
<path fill="#34A853"
d="M -14.754 63.239 C -11.514 63.239 -8.804 62.159 -6.824 60.329 L -10.684 57.329 C -11.764 58.049 -13.134 58.489 -14.754 58.489 C -17.884 58.489 -20.534 56.379 -21.484 53.529 L -25.464 53.529 L -25.464 56.619 C -23.494 60.539 -19.444 63.239 -14.754 63.239 Z" />
<path fill="#FBBC05"
d="M -21.484 53.529 C -21.734 52.809 -21.864 52.039 -21.864 51.239 C -21.864 50.439 -21.724 49.669 -21.484 48.949 L -21.484 45.859 L -25.464 45.859 C -26.284 47.479 -26.754 49.299 -26.754 51.239 C -26.754 53.179 -26.284 54.999 -25.464 56.619 L -21.484 53.529 Z" />
<path fill="#EA4335"
d="M -14.754 43.989 C -12.984 43.989 -11.404 44.599 -10.154 45.789 L -6.734 42.369 C -8.804 40.429 -11.514 39.239 -14.754 39.239 C -19.444 39.239 -23.494 41.939 -25.464 45.859 L -21.484 48.949 C -20.534 46.099 -17.884 43.989 -14.754 43.989 Z" />
</g>
</svg>
Sign up with Google
</a>
</div>
</div>
<div class="mt-6 text-center">
<p class="text-sm text-gray-600">
Already have an account?
<a class="underline" href="/auth/signin" rel="ugc" hx-get="/auth/signin" hx-swap="outerHTML" hx-push-url="true"
hx-target="#content" class="font-medium text-indigo-600 hover:text-indigo-500">
Log in
</a>
</p>
</div>
</div>
<script src="/public/validatePassword.js" />
</div>
}
}
templ Main(title string, err types.Message) {
@form(err, title)
}
templ EmailSend(title string) {
@layout.Base(title){
<style>
h1,
h2,
h3,
h4,
h5,
h6 {
font-family: 'Arimo', sans-serif;
--font-sans: 'Arimo';
}
</style>
<style>
body {
font-family: 'Libre Franklin', sans-serif;
--font-sans: 'Libre Franklin';
}
</style>
<div class="flex flex-col items-center justify-center min-h-[80vh] gap-6">
<div class="flex items-center justify-center">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
class="h-16 w-16 text-gray-500 dark:text-gray-400">
<rect width="20" height="16" x="2" y="4" rx="2"></rect>
<path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"></path>
</svg>
</div>
<div class="space-y-2 text-center">
<h1 class="text-3xl font-bold">Email Verification Sent</h1>
<p class="text-gray-500 dark:text-gray-400">
We've sent a verification email to your inbox. Please check your email and follow the instructions to verify your
account.
</p>
</div>
</div>
}
}
templ VerifySuccess(title string) {
@layout.Base(title){
<style>
h1,
h2,
h3,
h4,
h5,
h6 {
font-family: 'Arimo', sans-serif;
--font-sans: 'Arimo';
}
</style>
<style>
body {
font-family: 'Libre Franklin', sans-serif;
--font-sans: 'Libre Franklin';
}
</style>
<div class="flex flex-col items-center justify-center min-h-[80vh] gap-6">
<div class="bg-green-500 text-white rounded-full p-4">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="h-8 w-8">
<polyline points="20 6 9 17 4 12"></polyline>
</svg>
</div>
<div class="space-y-2 text-center">
<h1 class="text-3xl font-bold">Account Verified</h1>
<p class="text-gray-500 dark:text-gray-400">
Your account has been successfully verified. You can now access all the features of our platform.
</p>
</div>
</div>
}
}

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.2.778
// templ: version: v0.2.786
package emailView
//lint:file-ignore SA4006 This context is only used if a nested component is present.
@ -29,7 +29,7 @@ func RegistrationEmail(name string, link string) templ.Component {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 1)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<!doctype html><html lang=\"en\"><head><meta charset=\"UTF-8\"><meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><title>Email Verification</title><style>\n body, html {\n margin: 0;\n padding: 0;\n font-family: Arial, sans-serif;\n font-size: 16px;\n line-height: 1.6;\n }\n\n .container {\n max-width: 600px;\n margin: 0 auto;\n padding: 20px;\n }\n\n h1 {\n color: #333;\n }\n\n .button {\n display: inline-block;\n padding: 10px 20px;\n background-color: black;\n color: white;\n text-decoration: none;\n border-radius: 5px;\n }\n\n .button:hover {\n background-color: #0056b3;\n }\n </style></head><body><div class=\"container\"><h1>Email Verification</h1><p>Dear ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -42,7 +42,7 @@ func RegistrationEmail(name string, link string) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 2)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(",</p><p>Please verify your email address by clicking the button below:</p><a href=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -51,7 +51,7 @@ func RegistrationEmail(name string, link string) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 3)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" class=\"button\">Verify Email</a><p>Or copy and paste this URL into a new tab of your browser: <a href=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -60,7 +60,7 @@ func RegistrationEmail(name string, link string) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 4)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"><br>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -73,7 +73,7 @@ func RegistrationEmail(name string, link string) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 5)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></p><p>If you did not request this verification, please disregard this email.</p><p>Thank you, <br>The Filekeeper Team</p></div></body></html>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -102,7 +102,7 @@ func ForgotPassword(name string, link string) templ.Component {
templ_7745c5c3_Var6 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 6)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<!doctype html><html lang=\"en\"><head><meta charset=\"UTF-8\"><meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><title>Email Verification</title><style>\n body, html {\n margin: 0;\n padding: 0;\n font-family: Arial, sans-serif;\n font-size: 16px;\n line-height: 1.6;\n }\n\n .container {\n max-width: 600px;\n margin: 0 auto;\n padding: 20px;\n }\n\n h1 {\n color: #333;\n }\n\n .button {\n display: inline-block;\n padding: 10px 20px;\n background-color: black;\n color: white;\n text-decoration: none;\n border-radius: 5px;\n }\n\n .button:hover {\n background-color: #0056b3;\n }\n </style></head><body><div class=\"container\"><h1>Password Change Request</h1><p>Dear ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -115,7 +115,7 @@ func ForgotPassword(name string, link string) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 7)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(",</p><p>Please verify your password change request by clicking the button below:</p><a href=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -124,7 +124,7 @@ func ForgotPassword(name string, link string) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 8)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" class=\"button\">Verify Password Change</a><p>Or copy and paste this URL into a new tab of your browser: <a href=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -133,7 +133,7 @@ func ForgotPassword(name string, link string) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 9)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"><br>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -146,7 +146,7 @@ func ForgotPassword(name string, link string) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 10)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></p><p>If you did not request this password change, please disregard this email.</p><p>Thank you, <br>The Filekeeper Team</p></div></body></html>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}

View File

@ -1,6 +1,6 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.2.778
// templ: version: v0.2.786
package errorView
//lint:file-ignore SA4006 This context is only used if a nested component is present.
@ -43,7 +43,7 @@ func NotFound(title string) templ.Component {
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 1)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"flex flex-col items-center justify-center w-full min-h-[calc(100vh-1rem)] py-10 text-center gap-4 md:gap-8\"><div class=\"space-y-2\"><h1 class=\"text-4xl font-bold tracking-tighter sm:text-5xl\">404 Not Found</h1><p class=\"max-w-[600px] text-gray-500 md:text-xl/relaxed lg:text-base/relaxed xl:text-xl/relaxed\">The page you are looking for does not exist. It might have been moved or deleted.</p></div><a class=\"inline-flex h-10 items-center rounded-md border border-gray-200 border-gray-200 bg-white px-8 text-sm font-medium shadow-sm gap-2 transition-colors hover:bg-gray-100 hover:text-gray-900 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-gray-950\" href=\"/\" hx-get=\"/\" hx-swap=\"outerHTML\" hx-push-url=\"true\" hx-target=\"#content\"><svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"w-4 h-4\"><path d=\"m9 18 6-6-6-6\"></path></svg></a></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -90,7 +90,7 @@ func InternalServerError(title string) templ.Component {
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 2)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<main class=\"container mx-auto px-4 md:px-6\"><div class=\"flex h-screen w-full flex-col items-center justify-center bg-white\"><image class=\"w-32 md:w-64 lg:w-128\" src=\"/public/InternalServerErrorIcon.svg\" alt=\"Cute Icon\"></image><div class=\"mx-auto max-w-md space-y-4 text-center\"><h1 class=\"text-4xl font-bold tracking-tight text-gray-900\">Oops! Something went wrong.</h1><p class=\"text-gray-500\">We're sorry, but an internal server error has occurred. Please try again later.</p><div class=\"grid gap-2\"><a class=\"inline-flex h-10 items-center justify-center rounded-md bg-gray-900 px-6 text-sm font-medium text-gray-50 shadow transition-colors hover:bg-gray-900/90 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-gray-950 disabled:pointer-events-none disabled:opacity-50\" href=\"/\" hx-get=\"/\" hx-swap=\"outerHTML\" hx-push-url=\"true\" hx-target=\"#content\">Go back to homepage</a></div></div></div></main>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}

File diff suppressed because one or more lines are too long

View File

@ -22,7 +22,7 @@ templ content(title string, user types.User) {
</a>
} else {
<a class="px-8 py-4 bg-black text-white text-lg font-semibold rounded-full hover:bg-black/90 transition-colors"
href="/signup" hx-get="/signup" hx-swap="innerHTML" hx-push-url="true" hx-target="#content">
href="/auth/signup" hx-get="/auth/signup" hx-swap="innerHTML" hx-push-url="true" hx-target="#content">
Sign up for free
</a>
}
@ -82,7 +82,7 @@ templ content(title string, user types.User) {
</a>
} else {
<a class="px-6 py-3 bg-black text-white font-semibold rounded-full hover:bg-black/90 transition-colors"
href="/signup" hx-get="/signup" hx-swap="innerHTML" hx-push-url="true" hx-target="#content">
href="/auth/signup" hx-get="/auth/signup" hx-swap="innerHTML" hx-push-url="true" hx-target="#content">
Create your free account
</a>
}

View File

@ -1,6 +1,6 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.2.778
// templ: version: v0.2.786
package indexView
//lint:file-ignore SA4006 This context is only used if a nested component is present.
@ -46,7 +46,7 @@ func content(title string, user types.User) templ.Component {
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 1)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"bg-gray-100\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -54,37 +54,37 @@ func content(title string, user types.User) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 2)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<main class=\"container mx-auto px-4 py-16\"><div class=\"text-center mb-16\"><h1 class=\"text-5xl font-bold mb-6 text-primary\">Your files, always within reach</h1><p class=\"text-xl mb-8 text-gray-600\">Store, access, and manage your files with ease. Filekeeper offers generous storage and seamless access from any device, completely free.</p>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if user.Authenticated {
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 3)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<a class=\"px-8 py-4 bg-black text-white text-lg font-semibold rounded-full hover:bg-black/90 transition-colors\" href=\"/user\" hx-get=\"/user\" hx-swap=\"innerHTML\" hx-push-url=\"true\" hx-target=\"#content\">Open Dashboard</a>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
} else {
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 4)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<a class=\"px-8 py-4 bg-black text-white text-lg font-semibold rounded-full hover:bg-black/90 transition-colors\" href=\"/auth/signup\" hx-get=\"/auth/signup\" hx-swap=\"innerHTML\" hx-push-url=\"true\" hx-target=\"#content\">Sign up for free</a>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 5)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><div class=\"grid grid-cols-1 md:grid-cols-2 gap-8 mb-16\"><div class=\"p-6 bg-white rounded-lg shadow-lg hover:shadow-xl transition-shadow\"><svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-12 w-12 text-primary mx-auto mb-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\"><path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M3 15a4 4 0 004 4h9a5 5 0 10-.1-9.999 5.002 5.002 0 10-9.78 2.096A4.001 4.001 0 003 15z\"></path></svg><h2 class=\"text-xl font-semibold mb-2\">Easy Access</h2><p class=\"text-gray-600\">Access your files with just a few clicks, anytime you need them.</p></div><div class=\"p-6 bg-white rounded-lg shadow-lg hover:shadow-xl transition-shadow\"><svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-12 w-12 text-primary mx-auto mb-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\"><path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4\"></path></svg><h2 class=\"text-xl font-semibold mb-2\">Generous Storage</h2><p class=\"text-gray-600\">Store all your important files with our spacious free storage.</p></div><div class=\"p-6 bg-white rounded-lg shadow-lg hover:shadow-xl transition-shadow\"><svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-12 w-12 text-primary mx-auto mb-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\"><path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z\"></path></svg><h2 class=\"text-xl font-semibold mb-2\">Access Anywhere</h2><p class=\"text-gray-600\">Use Filekeeper on any device - computer, tablet, or smartphone.</p></div><div class=\"p-6 bg-white rounded-lg shadow-lg hover:shadow-xl transition-shadow\"><svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-12 w-12 text-primary mx-auto mb-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\"><path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z\"></path></svg><h2 class=\"text-xl font-semibold mb-2\">Secure Storage</h2><p class=\"text-gray-600\">Rest easy knowing your files are stored securely in the cloud.</p></div></div><div class=\"bg-zinc-800 text-white rounded-lg p-8 mb-16\"><h2 class=\"text-3xl font-bold mb-4\">Why choose Filekeeper?</h2><ul class=\"list-disc list-inside space-y-2\"><li>Completely free to use</li><li>Intuitive and user-friendly interface</li><li>Generous storage space for all your files</li><li>Access your files from any device, anywhere</li><li>Robust file organization and search capabilities</li><li>Dedicated customer support team</li></ul></div><div class=\"bg-white rounded-lg p-8 shadow-lg\"><h2 class=\"text-3xl font-bold mb-4 text-center\">Get Started with Filekeeper</h2><p class=\"text-center mb-6\">Join Filekeeper today and experience hassle-free file management - no credit card required!</p><div class=\"flex justify-center space-x-4\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if user.Authenticated {
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 6)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<a class=\"px-6 py-3 bg-black text-white font-semibold rounded-full hover:bg-black/90 transition-colors\" href=\"/user\" hx-get=\"/user\" hx-swap=\"innerHTML\" hx-push-url=\"true\" hx-target=\"#content\">Open Dashboard</a>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
} else {
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 7)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<a class=\"px-6 py-3 bg-black text-white font-semibold rounded-full hover:bg-black/90 transition-colors\" href=\"/auth/signup\" hx-get=\"/auth/signup\" hx-swap=\"innerHTML\" hx-push-url=\"true\" hx-target=\"#content\">Create your free account</a>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 8)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></div></main>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -92,7 +92,7 @@ func content(title string, user types.User) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 9)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}

View File

@ -180,10 +180,10 @@ templ Navbar(user types.User) {
</div>
</div>
} else {
<a href="/signup" class="text-gray-600 hover:text-gray-800" hx-get="/signup" hx-swap="outerHTML" hx-push-url="true" hx-target="#content">
<a href="/auth/signup" class="text-gray-600 hover:text-gray-800" hx-get="/auth/signup" hx-swap="outerHTML" hx-push-url="true" hx-target="#content">
Sign up
</a>
<a href="/signin" class="text-gray-600 hover:text-gray-800" hx-get="/signin" hx-swap="outerHTML" hx-push-url="true" hx-target="#content">
<a href="/auth/signin" class="text-gray-600 hover:text-gray-800" hx-get="/auth/signin" hx-swap="outerHTML" hx-push-url="true" hx-target="#content">
Sign in
</a>
}

View File

@ -1,6 +1,6 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.2.778
// templ: version: v0.2.786
package layout
//lint:file-ignore SA4006 This context is only used if a nested component is present.
@ -31,7 +31,7 @@ func Base(title string) templ.Component {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 1)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<!doctype html><html lang=\"en\"><head><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><meta name=\"description\" content=\"Secure and reliable file hosting service. Upload, organize, and share your documents, images, videos, and more. Sign up now to keep your files always within reach.\"><meta name=\"keywords\" content=\"file hosting, file sharing, cloud storage, data storage, secure file hosting, filekeeper, drive, mega\"><meta name=\"author\" content=\"Filekeeper\"><link href=\"/public/output.css\" rel=\"stylesheet\"><title>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -44,7 +44,7 @@ func Base(title string) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 2)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</title><script src=\"https://unpkg.com/htmx.org@1.9.12\"></script></head><body>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -52,7 +52,7 @@ func Base(title string) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 3)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div id=\"content\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -60,7 +60,7 @@ func Base(title string) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 4)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -72,7 +72,7 @@ func Base(title string) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 5)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</body></html>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -101,7 +101,7 @@ func BaseAuth(title string) templ.Component {
templ_7745c5c3_Var3 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 6)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<!doctype html><html lang=\"en\"><head><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><meta name=\"description\" content=\"Secure and reliable file hosting service. Upload, organize, and share your documents, images, videos, and more. Sign up now to keep your files always within reach.\"><meta name=\"keywords\" content=\"file hosting, file sharing, cloud storage, data storage, secure file hosting, filekeeper, drive, mega\"><meta name=\"author\" content=\"Filekeeper\"><link href=\"/public/output.css\" rel=\"stylesheet\"><title>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -114,7 +114,7 @@ func BaseAuth(title string) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 7)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</title><script src=\"https://unpkg.com/htmx.org@1.9.12\"></script><script src=\"/public/main.js\"></script></head><body>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -122,7 +122,7 @@ func BaseAuth(title string) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 8)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div id=\"content\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -130,7 +130,7 @@ func BaseAuth(title string) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 9)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -146,7 +146,7 @@ func BaseAuth(title string) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 10)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<script type=\"text/javascript\">\n function showFileUploadBox() {\n document.getElementById('FileUploadBox').classList.remove('hidden');\n }\n </script></body></html>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -175,7 +175,7 @@ func modal() templ.Component {
templ_7745c5c3_Var5 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 11)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div id=\"modalContainer\" class=\"fixed inset-0 z-50 flex items-center justify-center hidden p-4 sm:p-6 md:p-8\"><div class=\"fixed inset-0 bg-black opacity-50 transition-opacity duration-300\"></div><div id=\"modal\" class=\"bg-white rounded-lg shadow-xl w-full max-w-sm sm:max-w-md md:max-w-lg lg:max-w-xl xl:max-w-2xl p-4 sm:p-6 md:p-8 relative z-10 overflow-y-auto max-h-[90vh]\"><h2 class=\"text-xl sm:text-2xl font-bold mb-4\">Modal Title</h2><div class=\"prose prose-sm sm:prose lg:prose-lg\"><p class=\"mb-4\">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p></div><button id=\"closeModal\" class=\"mt-6 bg-red-500 hover:bg-red-600 text-white font-bold py-2 px-4 rounded transition duration-200 ease-in-out\">Close</button></div></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -204,7 +204,7 @@ func uploadBox() templ.Component {
templ_7745c5c3_Var6 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 12)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"hidden\" id=\"uploadBox\"><div class=\"fixed bottom-6 right-6 w-80 bg-white rounded-lg shadow-lg border border-gray-200 overflow-hidden\"><div class=\"p-4 bg-gray-100 flex justify-between items-center\"><div class=\"flex items-center\"><span class=\"font-medium text-base\">Mengupload 1 item</span> <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-5 w-5 ml-2 text-gray-500\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\"><path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M19 9l-7 7-7-7\"></path></svg></div><button class=\"text-gray-500 hover:text-gray-700\"><svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-5 w-5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\"><path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\"></path></svg></button></div><div id=\"FileUploadBoxItem\"></div></div></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -233,7 +233,7 @@ func MainScript() templ.Component {
templ_7745c5c3_Var7 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 13)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<script type=\"text/javascript\">\n function addScript() {\n if (!window.scriptAdded) {\n const script = document.createElement('script');\n script.src = \"/public/main.js\";\n window.scriptAdded = true;\n script.onerror = onerror;\n document.head.appendChild(script);\n }\n }\n addScript()\n </script>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -262,7 +262,7 @@ func modalScript() templ.Component {
templ_7745c5c3_Var8 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 14)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<script type=\"text/javascript\">\n window.modalContainer = document.getElementById('modalContainer');\n window.closeModalBtn = document.getElementById('closeModal');\n window.content = document.getElementById('content');\n function toggleModal() {\n window.modalContainer.classList.contains('hidden')\n ? modalContainer.classList.remove('hidden')\n : modalContainer.classList.add('hidden');\n }\n\n window.closeModalBtn.addEventListener('click', toggleModal);\n window.modalContainer.addEventListener('click', function(event) {\n if (event.target === modalContainer) {\n toggleModal();\n }\n })\n </script>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -291,12 +291,12 @@ func Navbar(user types.User) templ.Component {
templ_7745c5c3_Var9 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 15)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<header class=\"flex items-center justify-between border-b border-gray-200 bg-white px-6 py-4\"><div class=\"flex items-center gap-4\"><a class=\"flex items-center gap-2\" href=\"#\"><img src=\"/public/brand.svg\" width=\"48\" height=\"48\" alt=\"Filekeeper Logo\"> <span class=\"text-lg font-semibold\">Filekeeper</span></a></div><div class=\"flex space-x-4\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if user.Authenticated {
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 16)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"flex items-center gap-4\"><div class=\"inline-flex items-center justify-center w-10 h-10 overflow-hidden bg-gray-100 rounded-full\"><svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" version=\"1.1\" width=\"256\" height=\"256\" viewBox=\"0 0 256 256\" xml:space=\"preserve\"><defs></defs> <g style=\"stroke: none; stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: none; fill-rule: nonzero; opacity: 1;\" transform=\"translate(1.4065934065934016 1.4065934065934016) scale(2.81 2.81)\"><circle cx=\"45\" cy=\"45\" r=\"44\" style=\"stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(178,178,178); fill-rule: nonzero; opacity: 1;\" transform=\" matrix(1 0 0 1 0 0) \"></circle> <circle cx=\"44.997\" cy=\"39.727000000000004\" r=\"19.817\" style=\"stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(109,109,109); fill-rule: nonzero; opacity: 1;\" transform=\" matrix(1 0 0 1 0 0) \"></circle> <path d=\"M 11.266 73.25 C 19.337 63.622 31.454 57.5 45 57.5 c 13.546 0 25.663 6.122 33.734 15.75 l 0 0 C 70.663 82.878 58.547 89 45 89 C 31.454 89 19.337 82.878 11.266 73.25 L 11.266 73.25 z\" style=\"stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(109,109,109); fill-rule: nonzero; opacity: 1;\" transform=\" matrix(1 0 0 1 0 0) \" stroke-linecap=\"round\"></path> <path d=\"M 45 90 C 20.187 90 0 69.813 0 45 C 0 20.187 20.187 0 45 0 c 24.813 0 45 20.187 45 45 C 90 69.813 69.813 90 45 90 z M 45 2 C 21.29 2 2 21.29 2 45 c 0 23.71 19.29 43 43 43 c 23.71 0 43 -19.29 43 -43 C 88 21.29 68.71 2 45 2 z\" style=\"stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(43,43,43); fill-rule: nonzero; opacity: 1;\" transform=\" matrix(1 0 0 1 0 0) \" stroke-linecap=\"round\"></path> <path d=\"M 78.734 73.25 c -6.576 -7.844 -15.837 -13.358 -26.368 -15.133 c 7.294 -2.925 12.451 -10.048 12.451 -18.387 c 0 -10.945 -8.873 -19.817 -19.817 -19.817 S 25.183 28.785 25.183 39.73 c 0 8.339 5.157 15.462 12.451 18.387 c -10.531 1.775 -19.793 7.29 -26.368 15.133 v 0 C 19.337 82.878 31.454 89 45 89 C 58.547 89 70.663 82.878 78.734 73.25 L 78.734 73.25 z\" style=\"stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(109,109,109); fill-rule: nonzero; opacity: 1;\" transform=\" matrix(1 0 0 1 0 0) \" stroke-linecap=\"round\"></path> <path d=\"M 45 90 c -13.344 0 -25.919 -5.871 -34.5 -16.107 L 9.961 73.25 l 0.539 -0.643 c 6.239 -7.441 14.692 -12.654 24.046 -14.883 c -6.379 -3.687 -10.363 -10.467 -10.363 -17.995 c 0 -11.479 9.339 -20.817 20.817 -20.817 s 20.817 9.339 20.817 20.817 c 0 7.528 -3.983 14.309 -10.362 17.995 c 9.354 2.229 17.808 7.441 24.046 14.883 l 0.538 0.643 l -0.538 0.643 C 70.919 84.129 58.344 90 45 90 z M 12.581 73.25 C 20.764 82.635 32.531 88 45 88 c 12.47 0 24.236 -5.365 32.419 -14.75 C 70.887 65.761 61.964 60.748 52.2 59.104 l -3.506 -0.591 l 3.3 -1.323 c 7.183 -2.882 11.823 -9.734 11.823 -17.46 c 0 -10.376 -8.441 -18.817 -18.817 -18.817 s -18.817 8.441 -18.817 18.817 c 0 7.726 4.641 14.578 11.823 17.46 l 3.3 1.323 L 37.8 59.104 C 28.037 60.748 19.114 65.76 12.581 73.25 z\" style=\"stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(43,43,43); fill-rule: nonzero; opacity: 1;\" transform=\" matrix(1 0 0 1 0 0) \" stroke-linecap=\"round\"></path></g></svg></div><div class=\"font-medium hidden sm:block\"><div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -309,7 +309,7 @@ func Navbar(user types.User) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 17)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><div class=\"text-sm text-gray-500\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -322,17 +322,17 @@ func Navbar(user types.User) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 18)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></div></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
} else {
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 19)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<a href=\"/auth/signup\" class=\"text-gray-600 hover:text-gray-800\" hx-get=\"/auth/signup\" hx-swap=\"outerHTML\" hx-push-url=\"true\" hx-target=\"#content\">Sign up</a> <a href=\"/auth/signin\" class=\"text-gray-600 hover:text-gray-800\" hx-get=\"/auth/signin\" hx-swap=\"outerHTML\" hx-push-url=\"true\" hx-target=\"#content\">Sign in</a>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 20)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></header>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -361,7 +361,7 @@ func Footer() templ.Component {
templ_7745c5c3_Var12 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 21)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<footer class=\"bg-white p-6 md:p-8 w-full bottom-0 border-t border-gray-200 w-full py-8\"><div class=\"container mx-auto flex flex-col items-center justify-between gap-6 md:flex-row\"><div class=\"flex items-center gap-2\"><img src=\"/public/brand.svg\" width=\"48\" height=\"48\" alt=\"Filekeeper Logo\"> <span class=\"text-lg font-semibold\">Filekeeper</span></div><nav class=\"flex flex-wrap items-center justify-center gap-4 text-sm font-medium\"><a class=\"hover:underline\" href=\"#\">Pricing</a> <a class=\"hover:underline\" href=\"#\">About</a> <a class=\"hover:underline\" href=\"#\">Contact</a> <a class=\"hover:underline\" href=\"#\">Terms</a> <a class=\"hover:underline\" href=\"#\">Privacy</a></nav><p class=\"text-sm text-gray-500\">© 2024 Filekeeper. All rights reserved.</p></div></footer>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}

View File

@ -1,66 +0,0 @@
package signinView
import (
"github.com/fossyy/filekeeper/types"
"github.com/fossyy/filekeeper/view/client/layout"
)
templ content(err types.Message, title string) {
@layout.Base(title){
<div class="dark flex items-center min-h-screen p-4 sm:p-6 bg-gray-900">
<div class="mx-auto w-full max-w-md space-y-8">
<header class="text-center">
<div class="space-y-2">
<h1 class="text-3xl font-bold text-white">Sign In</h1>
<p class="text-gray-500 dark:text-gray-400">Enter your email or username below to login to your account</p>
switch err.Code {
case 0:
<div class="p-4 mb-4 text-sm text-red-800 rounded-lg bg-red-50 dark:bg-gray-800 dark:text-red-400" role="alert">
{err.Message}
</div>
}
</div>
</header>
<form class="space-y-4" method="post" action="">
<div class="space-y-2">
<label class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 text-white" for="email">Email</label>
<input type="email" class="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:bg-gray-800 dark:text-white" id="email" name="email" placeholder="m@example.com" required="" />
</div>
<div class="space-y-2">
<div class="flex items-center">
<label class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 text-white" for="password">Password</label>
<a class="ml-auto inline-block text-sm underline text-gray-300 dark:text-gray-400" href="/forgot-password" rel="ugc" hx-get="/forgot-password" hx-swap="outerHTML" hx-push-url="true" hx-target="#content">
Forgot your password?
</a>
</div>
<input type="password" class="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:bg-gray-800 dark:text-white" id="password" name="password" required="" />
</div>
<button class="bg-slate-200 inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-10 px-4 py-2 w-full" type="submit">
Login
</button>
</form>
<div
class="my-4 flex items-center before:mt-0.5 before:flex-1 before:border-t before:border-neutral-300 after:mt-0.5 after:flex-1 after:border-t after:border-neutral-300">
<p
class="mx-4 mb-0 text-white text-center font-semibold">
OR
</p>
</div>
<a href="/auth/google" class="inline-flex items-center justify-center p-5 text-base font-medium text-gray-500 rounded-lg bg-gray-50 hover:text-gray-900 hover:bg-gray-100 h-10 px-4 py-2 w-full">
<svg class="h-6 w-6 mr-2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="800px" height="800px" viewBox="-0.5 0 48 48" version="1.1"> <title>Google-color</title> <desc>Created with Sketch.</desc> <defs> </defs> <g id="Icons" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> <g id="Color-" transform="translate(-401.000000, -860.000000)"> <g id="Google" transform="translate(401.000000, 860.000000)"> <path d="M9.82727273,24 C9.82727273,22.4757333 10.0804318,21.0144 10.5322727,19.6437333 L2.62345455,13.6042667 C1.08206818,16.7338667 0.213636364,20.2602667 0.213636364,24 C0.213636364,27.7365333 1.081,31.2608 2.62025,34.3882667 L10.5247955,28.3370667 C10.0772273,26.9728 9.82727273,25.5168 9.82727273,24" id="Fill-1" fill="#FBBC05"> </path> <path d="M23.7136364,10.1333333 C27.025,10.1333333 30.0159091,11.3066667 32.3659091,13.2266667 L39.2022727,6.4 C35.0363636,2.77333333 29.6954545,0.533333333 23.7136364,0.533333333 C14.4268636,0.533333333 6.44540909,5.84426667 2.62345455,13.6042667 L10.5322727,19.6437333 C12.3545909,14.112 17.5491591,10.1333333 23.7136364,10.1333333" id="Fill-2" fill="#EB4335"> </path> <path d="M23.7136364,37.8666667 C17.5491591,37.8666667 12.3545909,33.888 10.5322727,28.3562667 L2.62345455,34.3946667 C6.44540909,42.1557333 14.4268636,47.4666667 23.7136364,47.4666667 C29.4455,47.4666667 34.9177955,45.4314667 39.0249545,41.6181333 L31.5177727,35.8144 C29.3995682,37.1488 26.7323182,37.8666667 23.7136364,37.8666667" id="Fill-3" fill="#34A853"> </path> <path d="M46.1454545,24 C46.1454545,22.6133333 45.9318182,21.12 45.6113636,19.7333333 L23.7136364,19.7333333 L23.7136364,28.8 L36.3181818,28.8 C35.6879545,31.8912 33.9724545,34.2677333 31.5177727,35.8144 L39.0249545,41.6181333 C43.3393409,37.6138667 46.1454545,31.6490667 46.1454545,24" id="Fill-4" fill="#4285F4"> </path> </g> </g> </g> </svg>
<span>Continue with Google</span>
</a>
<div class="text-center text-sm text-white">
Don't have an account?
<a class="underline" href="/signup" rel="ugc" hx-get="/signup" hx-swap="outerHTML" hx-push-url="true" hx-target="#content">
Sign up
</a>
</div>
</div>
</div>
}
}
templ Main(title string, err types.Message) {
@content(err, title)
}

View File

@ -1,116 +0,0 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.2.778
package signinView
//lint:file-ignore SA4006 This context is only used if a nested component is present.
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
import (
"github.com/fossyy/filekeeper/types"
"github.com/fossyy/filekeeper/view/client/layout"
)
func content(err types.Message, title string) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
if templ_7745c5c3_Var1 == nil {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Var2 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 1)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
switch err.Code {
case 0:
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 2)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(err.Message)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/client/signin/signin.templ`, Line: 19, Col: 38}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 3)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 4)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
templ_7745c5c3_Err = layout.Base(title).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
func Main(title string, err types.Message) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var4 := templ.GetChildren(ctx)
if templ_7745c5c3_Var4 == nil {
templ_7745c5c3_Var4 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = content(err, title).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
var _ = templruntime.GeneratedTemplate

View File

@ -1,159 +0,0 @@
package signup
import (
"github.com/fossyy/filekeeper/types"
"github.com/fossyy/filekeeper/view/client/layout"
)
templ form(err types.Message, title string) {
@layout.Base(title){
<div class="dark flex items-center min-h-screen p-4 sm:p-6 bg-gray-900">
<div class="mx-auto w-full max-w-md space-y-8">
<header class="text-center">
<div class="space-y-2">
<h1 class="text-3xl font-bold text-white">Sign Up</h1>
<p class="text-gray-500 dark:text-gray-400">Enter your information to create an account</p>
switch err.Code {
case 0:
<div class="p-4 mb-4 text-sm text-red-800 rounded-lg bg-red-50 dark:bg-gray-800 dark:text-red-400" role="alert">
{err.Message}
</div>
case 1:
<div class="p-4 mb-4 text-sm text-green-800 rounded-lg bg-green-50 dark:bg-gray-800 dark:text-green-400" role="alert">
{err.Message}
</div>
}
</div>
</header>
<form class="space-y-4" method="post" action="">
<div class="space-y-2">
<label class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 text-white" for="email">Email</label>
<input type="email" class="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:bg-gray-800 dark:text-white" id="email" name="email" placeholder="m@example.com" required="" />
</div>
<div class="space-y-2">
<div class="flex items-center">
<label class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 text-white" for="password">Username</label>
</div>
<input type="text" class="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:bg-gray-800 dark:text-white" id="username" name="username" required="" />
</div>
<div class="space-y-2">
<label class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 text-white" for="password">Password</label>
<input type="password" class="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:bg-gray-800 dark:text-white" id="password" name="password" required />
</div>
<div class="space-y-2">
<label class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 text-white" for="confirmPassword">Confirm Password</label>
<input type="password" class="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:bg-gray-800 dark:text-white" id="confirmPassword" required />
</div>
<div class="flex justify-start mt-3 ml-4 p-1">
<ul>
<li class="flex items-center py-1">
<div id="matchSvgContainer" class="rounded-full p-1 fill-current bg-red-200 text-green-700">
<svg id="matchSvgIcon" class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path id="matchGoodPath" style="display: none;" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
<path id="matchBadPath" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
</svg>
</div>
<span id="matchStatusText" class="font-medium text-sm ml-3 text-red-700"> Passwords do not match</span>
</li>
<li class="flex items-center py-1">
<div id="uppercaseSvgContainer" class="rounded-full p-1 fill-current bg-red-200 text-green-700">
<svg id="uppercaseSvgIcon" class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path id="uppercaseGoodPath" style="display: none;" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
<path id="uppercaseBadPath" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
</svg>
</div>
<span id="uppercaseStatusText" class="font-medium text-sm ml-3 text-red-700"> Password must contain at least one uppercase letter</span>
</li>
<li class="flex items-center py-1">
<div id="lengthSvgContainer" class="rounded-full p-1 fill-current bg-red-200 text-green-700">
<svg id="lengthSvgIcon" class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path id="lengthGoodPath" style="display: none;" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
<path id="lengthBadPath" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
</svg>
</div>
<span id="lengthStatusText" class="font-medium text-sm ml-3 text-red-700"> Password length must be at least 8 characters</span>
</li>
</ul>
</div>
<button class="bg-slate-200 inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-10 px-4 py-2 w-full" type="submit" id="submit" name="submit" disabled>
Sign up
</button>
</form>
<div class="text-center text-sm text-white">
Already have an account?
<a class="underline" href="/signin" rel="ugc" hx-get="/signin" hx-swap="outerHTML" hx-push-url="true" hx-target="#content">
Sign in
</a>
</div>
</div>
</div>
<script src="/public/validatePassword.js" />
}
}
templ Main(title string, err types.Message) {
@form(err, title)
}
templ EmailSend(title string) {
@layout.Base(title){
<style>h1, h2, h3, h4, h5, h6 { font-family: 'Arimo', sans-serif; --font-sans: 'Arimo'; }</style>
<style>body { font-family: 'Libre Franklin', sans-serif; --font-sans: 'Libre Franklin'; }</style>
<div class="flex flex-col items-center justify-center min-h-[80vh] gap-6">
<div class="flex items-center justify-center">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="h-16 w-16 text-gray-500 dark:text-gray-400"
>
<rect width="20" height="16" x="2" y="4" rx="2"></rect>
<path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"></path>
</svg>
</div>
<div class="space-y-2 text-center">
<h1 class="text-3xl font-bold">Email Verification Sent</h1>
<p class="text-gray-500 dark:text-gray-400">
We've sent a verification email to your inbox. Please check your email and follow the instructions to verify your account.
</p>
</div>
</div>
}
}
templ VerifySuccess(title string) {
@layout.Base(title){
<style>h1, h2, h3, h4, h5, h6 { font-family: 'Arimo', sans-serif; --font-sans: 'Arimo'; }</style>
<style>body { font-family: 'Libre Franklin', sans-serif; --font-sans: 'Libre Franklin'; }</style>
<div class="flex flex-col items-center justify-center min-h-[80vh] gap-6">
<div class="bg-green-500 text-white rounded-full p-4">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="h-8 w-8"
>
<polyline points="20 6 9 17 4 12"></polyline>
</svg>
</div>
<div class="space-y-2 text-center">
<h1 class="text-3xl font-bold">Account Verified</h1>
<p class="text-gray-500 dark:text-gray-400">
Your account has been successfully verified. You can now access all the features of our platform.
</p>
</div>
</div>
}
}

View File

@ -1,228 +0,0 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.2.778
package signup
//lint:file-ignore SA4006 This context is only used if a nested component is present.
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
import (
"github.com/fossyy/filekeeper/types"
"github.com/fossyy/filekeeper/view/client/layout"
)
func form(err types.Message, title string) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
if templ_7745c5c3_Var1 == nil {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Var2 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 1)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
switch err.Code {
case 0:
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 2)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(err.Message)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/client/signup/signup.templ`, Line: 19, Col: 38}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 3)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
case 1:
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 4)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(err.Message)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/client/signup/signup.templ`, Line: 23, Col: 38}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 5)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 6)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
templ_7745c5c3_Err = layout.Base(title).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
func Main(title string, err types.Message) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var5 := templ.GetChildren(ctx)
if templ_7745c5c3_Var5 == nil {
templ_7745c5c3_Var5 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = form(err, title).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
func EmailSend(title string) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var6 := templ.GetChildren(ctx)
if templ_7745c5c3_Var6 == nil {
templ_7745c5c3_Var6 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Var7 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 7)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
templ_7745c5c3_Err = layout.Base(title).Render(templ.WithChildren(ctx, templ_7745c5c3_Var7), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
func VerifySuccess(title string) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var8 := templ.GetChildren(ctx)
if templ_7745c5c3_Var8 == nil {
templ_7745c5c3_Var8 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Var9 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 8)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
templ_7745c5c3_Err = layout.Base(title).Render(templ.WithChildren(ctx, templ_7745c5c3_Var9), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
var _ = templruntime.GeneratedTemplate

View File

@ -1,6 +1,6 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.2.778
// templ: version: v0.2.786
package totpView
//lint:file-ignore SA4006 This context is only used if a nested component is present.
@ -46,13 +46,13 @@ func content(title string, msg types.Message) templ.Component {
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 1)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<main class=\"container mx-auto px-4 py-12 md:px-6 md:py-16 lg:py-10\"><div class=\"flex min-h-screen items-center justify-center bg-background px-4 py-12 sm:px-6 lg:px-8\"><div class=\"w-full max-w-md space-y-8\"><div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
switch msg.Code {
case 0:
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 2)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"flex items-center p-4 mb-4 text-sm text-red-800 rounded-lg bg-red-50\" role=\"alert\"><svg class=\"flex-shrink-0 inline w-4 h-4 me-3\" aria-hidden=\"true\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"currentColor\" viewBox=\"0 0 20 20\"><path d=\"M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5ZM9.5 4a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3ZM12 15H8a1 1 0 0 1 0-2h1v-3H8a1 1 0 0 1 0-2h2a1 1 0 0 1 1 1v4h1a1 1 0 0 1 0 2Z\"></path></svg> <span class=\"sr-only\">Info</span><div><span class=\"font-medium\">Error!</span> ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -65,12 +65,12 @@ func content(title string, msg types.Message) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 3)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 4)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<h2 class=\"mt-6 text-center text-3xl font-bold tracking-tight text-foreground\">Verify Your Identity</h2><p class=\"mt-2 text-center text-sm text-muted-foreground\">Please enter the 6-digit code generated by your authentication app to complete the login process.</p></div><form class=\"space-y-6\" method=\"POST\"><div><label for=\"code\" class=\"block text-sm font-medium text-muted-foreground\">Verification Code</label><div class=\"mt-1\"><input class=\"h-10 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 block w-full appearance-none rounded-md border border-input bg-background px-3 py-2 placeholder-muted-foreground shadow-sm focus:border-primary focus:outline-none focus:ring-primary sm:text-sm\" id=\"code\" autocomplete=\"one-time-code\" required=\"\" placeholder=\"123456\" pattern=\"[0-9]{6}\" maxlength=\"6\" type=\"text\" name=\"code\"></div></div><div><button class=\"items-center whitespace-nowrap ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 h-10 flex w-full justify-center rounded-md bg-black py-2 px-4 text-sm font-medium text-primary-foreground shadow-sm text-white hover:bg-primary/90 focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2\" type=\"submit\">Verify Code</button></div></form></div></div></main>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}

View File

@ -1,6 +1,6 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.2.778
// templ: version: v0.2.786
package userTotpSetupView
//lint:file-ignore SA4006 This context is only used if a nested component is present.
@ -81,7 +81,7 @@ func MainContent(title string, qrcode string, code string, user types.User, msg
templ_7745c5c3_Var3 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 1)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<title>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -94,7 +94,7 @@ func MainContent(title string, qrcode string, code string, user types.User, msg
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 2)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</title>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -102,13 +102,13 @@ func MainContent(title string, qrcode string, code string, user types.User, msg
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 3)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<main class=\"container mx-auto px-4 py-12 md:px-6 md:py-16 lg:py-10\"><a class=\"inline-flex items-center space-x-2 rounded-md bg-muted px-4 py-2 text-sm font-medium text-muted-foreground transition-colors hover:bg-muted/80 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2\" href=\"/user\" hx-get=\"/user\" hx-swap=\"innerHTML\" hx-push-url=\"true\" hx-target=\"#content\" rel=\"ugc\"><svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"h-4 w-4\"><path d=\"m12 19-7-7 7-7\"></path> <path d=\"M19 12H5\"></path></svg> <span>Back</span></a><div class=\"mx-auto max-w-md px-4 py-12 sm:px-6 lg:px-8\"><div class=\"space-y-6 text-center\"><div class=\"flex items-center\"><h1 class=\"text-3xl font-bold\">Set up Two-Factor Authentication</h1></div><p class=\"text-muted-foreground\">Secure your account with time-based one-time passwords (TOTP).</p><div class=\"mt-4 text-left text-muted-foreground\"><p>Here's how to set up the Google Authenticator app:</p><ol class=\"list-decimal pl-6\"><li>Download the Google Authenticator app on your mobile device.</li><li>Open the app and tap \"Begin Setup\".</li><li>Select \"Scan a barcode\" and point your camera at the QR code below.</li><li>The app will automatically add your account and display a 6-digit code.</li><li>Enter this code on the website to complete the setup.</li></ol></div></div><div class=\"rounded-lg border rounded-lg bg-muted p-6bg-card text-card-foreground shadow-sm mt-5\" data-v0-t=\"card\"><div class=\"p-6 space-y-6\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
switch msg.Code {
case 0:
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 4)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"flex items-center p-4 mb-4 text-sm text-red-800 rounded-lg bg-red-50\" role=\"alert\"><svg class=\"flex-shrink-0 inline w-4 h-4 me-3\" aria-hidden=\"true\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"currentColor\" viewBox=\"0 0 20 20\"><path d=\"M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5ZM9.5 4a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3ZM12 15H8a1 1 0 0 1 0-2h1v-3H8a1 1 0 0 1 0-2h2a1 1 0 0 1 1 1v4h1a1 1 0 0 1 0 2Z\"></path></svg> <span class=\"sr-only\">Info</span><div><span class=\"font-medium\">Error!</span> ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -121,12 +121,12 @@ func MainContent(title string, qrcode string, code string, user types.User, msg
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 5)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
case 1:
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 6)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"flex items-center p-4 mb-4 text-sm text-green-800 rounded-lg bg-green-50\" role=\"alert\"><svg class=\"flex-shrink-0 inline w-4 h-4 me-3\" aria-hidden=\"true\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"currentColor\" viewBox=\"0 0 20 20\"><path d=\"M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5ZM9.5 4a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3ZM12 15H8a1 1 0 0 1 0-2h1v-3H8a1 1 0 0 1 0-2h2a1 1 0 0 1 1 1v4h1a1 1 0 0 1 0 2Z\"></path></svg> <span class=\"sr-only\">Info</span><div><span class=\"font-medium\">Success!</span> ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -139,12 +139,12 @@ func MainContent(title string, qrcode string, code string, user types.User, msg
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 7)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 8)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"flex items-center justify-center\"><img src=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -157,7 +157,7 @@ func MainContent(title string, qrcode string, code string, user types.User, msg
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 9)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" width=\"200\" height=\"200\" alt=\"QR Code\" class=\"rounded-lg\" style=\"aspect-ratio: 200 / 200; object-fit: cover;\"></div><div class=\"mt-6 space-y-2\"><p class=\"font-medium\">Backup Code:</p><div class=\"rounded-md bg-background px-4 py-2 text-sm font-mono text-muted-foreground\">----|----</div><p class=\"font-medium\">TOTP Secret:</p><div class=\"rounded-md bg-background px-4 py-2 text-sm font-mono text-muted-foreground\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -170,7 +170,7 @@ func MainContent(title string, qrcode string, code string, user types.User, msg
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 10)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></div><form method=\"post\" action=\"/user/totp/setup\"><div class=\"grid gap-2\"><label class=\"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70\" for=\"totp\">Totp Code</label> <input id=\"secret\" name=\"secret\" value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -183,7 +183,7 @@ func MainContent(title string, qrcode string, code string, user types.User, msg
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 11)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" type=\"hidden\"> <input class=\"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50\" id=\"totp\" name=\"totp\" placeholder=\"Code from authenticator app\"><div class=\"flex items-center p-6\"><button class=\"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 border border-input bg-background hover:bg-accent hover:text-accent-foreground text-primary-foreground hover:bg-primary/90 h-10 px-4 py-2 w-full\" type=\"submit\">Enable TOTP</button></div></div></form></div></div></div></main>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}

View File

@ -181,7 +181,7 @@ templ MainContent(title string, user types.User, allowance *types.Allowance, Lis
class="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
type="password" id="confirmPassword" placeholder="New password confirmation" />
</div>
<div id="validationBox" class="justify-start mt-3 ml-4 p-1 hidden">
<div id="checkContainer" class="justify-start mt-3 ml-4 p-1 hidden">
<ul>
<li class="flex items-center py-1">
<div id="matchSvgContainer" class="rounded-full p-1 fill-current bg-red-200 text-green-700">
@ -292,15 +292,6 @@ templ MainContent(title string, user types.User, allowance *types.Allowance, Lis
@layout.Footer()
@templ.JSONScript("AllowanceUsedPercent", allowance.AllowanceUsedPercent)
<script type="text/javascript">
document.getElementById('currentPassword').addEventListener('input', function() {
var validationBox = document.getElementById('validationBox');
if (this.value.length > 0) {
validationBox.classList.remove('hidden');
} else {
validationBox.classList.add('hidden');
}
});
window.allowanceProgress = document.getElementById(`allowanceProgress`);
window.AllowanceUsedPercent = JSON.parse(document.getElementById('AllowanceUsedPercent').textContent);
allowanceProgress.style.width = `${AllowanceUsedPercent}%`;

File diff suppressed because one or more lines are too long