Add password validation
This commit is contained in:
76
view/download/download.templ
Normal file
76
view/download/download.templ
Normal file
@ -0,0 +1,76 @@
|
||||
package downloadView
|
||||
|
||||
import (
|
||||
"github.com/fossyy/filekeeper/view/layout"
|
||||
"github.com/fossyy/filekeeper/types"
|
||||
)
|
||||
|
||||
templ component(title string, files []types.FileData){
|
||||
@layout.Base(title){
|
||||
<div class="dark min-h-screen p-4 sm:p-6 bg-gray-900 text-white">
|
||||
<div class="space-y-4">
|
||||
<header class="text-center">
|
||||
<div class="space-y-2">
|
||||
<h1 class="text-3xl font-bold tracking-tighter sm:text-4xl">Download Files</h1>
|
||||
</div>
|
||||
</header>
|
||||
<div class="mx-auto grid w-full max-w-3xl gap-4 px-4">
|
||||
for _, file := range files {
|
||||
<div class="rounded-lg border bg-card text-card-foreground shadow-sm">
|
||||
<div class="flex space-y-4 flex-col p-4">
|
||||
<div class="space-y-1">
|
||||
<h2 class="text-lg font-bold tracking-wide">{ file.Name }</h2>
|
||||
<p class="text-sm leading-none"> { file.Size }</p>
|
||||
</div>
|
||||
<div class="space-x-2">
|
||||
<button class="inline-flex items-center justify-center whitespace-nowrap 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 h-9 rounded-md px-3">
|
||||
<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="M4 13.5V4a2 2 0 0 1 2-2h8.5L20 7.5V20a2 2 0 0 1-2 2h-5.5"></path>
|
||||
<polyline points="14 2 14 8 20 8"></polyline>
|
||||
<path d="M10.42 12.61a2.1 2.1 0 1 1 2.97 2.97L7.95 21 4 22l.99-3.95 5.43-5.44Z"></path>
|
||||
</svg>
|
||||
<span class="sr-only">Edit</span>
|
||||
</button>
|
||||
<a href={ templ.SafeURL("/download/" + file.ID) } 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 dark:text-gray-400 dark:bg-gray-800 dark:hover:bg-gray-700 dark:hover:text-white">
|
||||
<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="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
|
||||
<polyline points="7 10 12 15 17 10"></polyline>
|
||||
<line x1="12" x2="12" y1="15" y2="3"></line>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
templ Main(title string, files []types.FileData){
|
||||
@component(title, files)
|
||||
}
|
111
view/email/email.templ
Normal file
111
view/email/email.templ
Normal file
@ -0,0 +1,111 @@
|
||||
package emailView
|
||||
|
||||
templ RegistrationEmail(name string, link string) {
|
||||
<!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>
|
||||
body, html {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.button {
|
||||
display: inline-block;
|
||||
padding: 10px 20px;
|
||||
background-color: black;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
background-color: #0056b3;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>Email Verification</h1>
|
||||
<p>Dear {name},</p>
|
||||
<p>Please verify your email address by clicking the button below:</p>
|
||||
<a href={ templ.SafeURL(link)} class="button">Verify Email</a>
|
||||
<p>Or copy and paste this URL into a new tab of your browser: <a href={ templ.SafeURL(link)}><br/>{link}</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>
|
||||
}
|
||||
|
||||
templ ForgotPassword(name string, link string) {
|
||||
<!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>
|
||||
body, html {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.button {
|
||||
display: inline-block;
|
||||
padding: 10px 20px;
|
||||
background-color: black;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
background-color: #0056b3;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>Password Change Request</h1>
|
||||
<p>Dear {name},</p>
|
||||
<p>Please verify your password change request by clicking the button below:</p>
|
||||
<a href={ templ.SafeURL(link)} class="button">Verify Password Change</a>
|
||||
<p>Or copy and paste this URL into a new tab of your browser: <a href={ templ.SafeURL(link)}><br/>{link}</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>
|
||||
}
|
39
view/error/error.templ
Normal file
39
view/error/error.templ
Normal file
@ -0,0 +1,39 @@
|
||||
package errorView
|
||||
|
||||
import "github.com/fossyy/filekeeper/view/layout"
|
||||
|
||||
templ content(title string){
|
||||
@layout.Base(title){
|
||||
<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 dark:text-gray-400">
|
||||
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 dark:border-gray-800 dark:border-gray-800 dark:bg-gray-950 dark:hover:bg-gray-800 dark:hover:text-gray-50 dark:focus-visible:ring-gray-300"
|
||||
href="/"
|
||||
>
|
||||
<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>
|
||||
}
|
||||
}
|
||||
|
||||
templ Main(title string) {
|
||||
@content(title)
|
||||
}
|
169
view/forgotPassword/forgotPassword.templ
Normal file
169
view/forgotPassword/forgotPassword.templ
Normal file
@ -0,0 +1,169 @@
|
||||
package forgotPasswordView
|
||||
|
||||
import (
|
||||
"github.com/fossyy/filekeeper/types"
|
||||
"github.com/fossyy/filekeeper/view/layout"
|
||||
)
|
||||
|
||||
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">
|
||||
<span class="font-medium">Danger alert!</span> {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>
|
||||
}
|
||||
}
|
||||
|
||||
templ Main(title string, err types.Message) {
|
||||
@content(title, err)
|
||||
}
|
||||
|
||||
templ NewPasswordForm(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">
|
||||
<span class="font-medium">Danger alert!</span> {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="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="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>
|
||||
<li class="flex items-center py-1">
|
||||
<div id="requirementsSvgContainer" class="rounded-full p-1 fill-current bg-red-200 text-green-700">
|
||||
<svg id="requirementsSvgIcon" class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path id="requirementsGoodPath" style="display: none;" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
|
||||
<path id="requirementsBadPath" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<span id="requirementsStatusText" class="font-medium text-sm ml-3 text-red-700">The password must contain at least one symbol (!@#$%^&*), one uppercase letter, and three numbers</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" />
|
||||
}
|
||||
}
|
||||
|
||||
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 change your password.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
templ ChangeSuccess(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">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>
|
||||
}
|
||||
}
|
103
view/index/index.templ
Normal file
103
view/index/index.templ
Normal file
@ -0,0 +1,103 @@
|
||||
package indexView
|
||||
|
||||
import (
|
||||
"github.com/fossyy/filekeeper/view/layout"
|
||||
)
|
||||
|
||||
templ content(title string) {
|
||||
@layout.Base(title){
|
||||
<div class="bg-white">
|
||||
<nav class="container mx-auto px-6 py-4 flex justify-between items-center">
|
||||
<a href="#" class="text-blue-500 text-xl font-semibold">
|
||||
C.
|
||||
</a>
|
||||
<div class="flex space-x-4">
|
||||
<a href="/signup" class="text-gray-600 hover:text-gray-800">
|
||||
Sign up
|
||||
</a>
|
||||
<a href="/signin" class="text-gray-600 hover:text-gray-800">
|
||||
Sign in
|
||||
</a>
|
||||
</div>
|
||||
</nav>
|
||||
<header class="container mx-auto px-6 py-16 text-center">
|
||||
<h1 class="text-5xl font-bold text-gray-900 mb-2">Your files, always within reach.</h1>
|
||||
<p class="text-gray-700 text-lg mb-8">
|
||||
Store, access, and share your files from anywhere. We offer secure and reliable file storage, so you can
|
||||
focus on what matters most.
|
||||
</p>
|
||||
<div class="flex justify-center items-center space-x-4">
|
||||
<div class="sm:flex sm:justify-center lg:justify-start">
|
||||
<div class="rounded-md shadow">
|
||||
<a class="w-full flex items-center justify-center px-8 py-3 text-base leading-6 font-medium rounded-md text-white bg-pink-400 hover:bg-pink-500 hover:text-white focus:ring ring-offset-2 ring-pink-400 focus:outline-none transition duration-150 ease-in-out md:py-4 md:text-lg md:px-10"
|
||||
href="/signup">
|
||||
Get started
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-center items-center space-x-4 mt-8">
|
||||
<div class="grid gap-4 md:gap-8 lg:gap-4 items-start sm:grid-cols-2">
|
||||
<div class="flex items-center space-x-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="w-6 h-6 flex-shrink-0 text-gray-500">
|
||||
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path>
|
||||
<polyline points="22 4 12 14.01 9 11.01"></polyline>
|
||||
</svg>
|
||||
<div class="text-sm font-medium leading-none md:text-base">
|
||||
Secure encryption to protect your data
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center space-x-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="w-6 h-6 flex-shrink-0 text-gray-500">
|
||||
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path>
|
||||
<polyline points="22 4 12 14.01 9 11.01"></polyline>
|
||||
</svg>
|
||||
<div class="text-sm font-medium leading-none md:text-base">
|
||||
Easy file sharing with customizable permissions
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center space-x-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="w-6 h-6 flex-shrink-0 text-gray-500">
|
||||
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path>
|
||||
<polyline points="22 4 12 14.01 9 11.01"></polyline>
|
||||
</svg>
|
||||
<div class="text-sm font-medium leading-none md:text-base">
|
||||
Unlimited storage capacity for your files
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center space-x-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="w-6 h-6 flex-shrink-0 text-gray-500">
|
||||
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path>
|
||||
<polyline points="22 4 12 14.01 9 11.01"></polyline>
|
||||
</svg>
|
||||
<div class="text-sm font-medium leading-none md:text-base">
|
||||
Seamless collaboration with built-in productivity tools
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
</div>
|
||||
<footer class="w-full border-t">
|
||||
<div class="container grid-inset py-12 gap-4 text-center md:gap-8 md:py-16">
|
||||
<div class="flex items-center justify-center gap-2 text-xs tracking-wide md:gap-4">
|
||||
<p class="text-gray-500 dark:text-gray-400">© 2023 Acme, Inc. All rights reserved.</p>
|
||||
<p class="text-gray-500 dark:text-gray-400">Terms of Service</p>
|
||||
<p class="text-gray-500 dark:text-gray-400">Privacy Policy</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
}
|
||||
}
|
||||
|
||||
templ Main(title string) {
|
||||
@content(title)
|
||||
}
|
16
view/layout/base.templ
Normal file
16
view/layout/base.templ
Normal file
@ -0,0 +1,16 @@
|
||||
package layout
|
||||
|
||||
templ Base(title string){
|
||||
<!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>{ title }</title>
|
||||
</head>
|
||||
<body>
|
||||
{ children... }
|
||||
</body>
|
||||
</html>
|
||||
}
|
55
view/signin/signin.templ
Normal file
55
view/signin/signin.templ
Normal file
@ -0,0 +1,55 @@
|
||||
package signinView
|
||||
|
||||
import (
|
||||
"github.com/fossyy/filekeeper/types"
|
||||
"github.com/fossyy/filekeeper/view/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">
|
||||
<span class="font-medium">Danger alert!</span> {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">
|
||||
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="text-center text-sm text-white">
|
||||
Don't have an account?
|
||||
<a class="underline" href="/signup" rel="ugc">
|
||||
Sign up
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
templ Main(title string, err types.Message) {
|
||||
@content(err, title)
|
||||
}
|
159
view/signup/signup.templ
Normal file
159
view/signup/signup.templ
Normal file
@ -0,0 +1,159 @@
|
||||
package signup
|
||||
|
||||
import (
|
||||
"github.com/fossyy/filekeeper/types"
|
||||
"github.com/fossyy/filekeeper/view/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 email 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">
|
||||
<span class="font-medium">Danger alert!</span> {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">
|
||||
<span class="font-medium">Success alert!</span> {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="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>
|
||||
<li class="flex items-center py-1">
|
||||
<div id="requirementsSvgContainer" class="rounded-full p-1 fill-current bg-red-200 text-green-700">
|
||||
<svg id="requirementsSvgIcon" class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path id="requirementsGoodPath" style="display: none;" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
|
||||
<path id="requirementsBadPath" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<span id="requirementsStatusText" class="font-medium text-sm ml-3 text-red-700">The password must contain at least one symbol (!@#$%^&*), one uppercase letter, and three numbers</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">
|
||||
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>
|
||||
}
|
||||
}
|
56
view/upload/upload.templ
Normal file
56
view/upload/upload.templ
Normal file
@ -0,0 +1,56 @@
|
||||
package uploadView
|
||||
|
||||
import "github.com/fossyy/filekeeper/view/layout"
|
||||
|
||||
templ content(title string) {
|
||||
@layout.Base(title){
|
||||
<div class="flex items-center min-h-screen p-4 sm:p-6 bg-gray-900 text-white">
|
||||
<div class="mx-auto w-full max-w-md space-y-8">
|
||||
<div class="rounded-lg border bg-card text-card-foreground shadow-sm w-full max-w-md" data-v0-t="card">
|
||||
<div class="flex flex-col space-y-1.5 p-4">
|
||||
<div class="flex items-center justify-center w-full">
|
||||
<label for="dropzone-file"
|
||||
class="flex flex-col items-center justify-center w-full h-64 border-2 border-gray-300 border-dashed rounded-lg cursor-pointer bg-gray-50 dark:hover:bg-bray-800 dark:bg-gray-700 hover:bg-gray-100 dark:border-gray-600 dark:hover:border-gray-500 dark:hover:bg-gray-600">
|
||||
<div class="flex flex-col items-center justify-center pt-5 pb-6">
|
||||
<svg class="w-8 h-8 mb-4 text-gray-400" aria-hidden="true"
|
||||
xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 20 16">
|
||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M13 13h3a3 3 0 0 0 0-6h-.025A5.56 5.56 0 0 0 16 6.5 5.5 5.5 0 0 0 5.207 5.021C5.137 5.017 5.071 5 5 5a4 4 0 0 0 0 8h2.167M10 15V6m0 0L8 8m2-2 2 2" />
|
||||
</svg>
|
||||
<p class="mb-2 text-sm text-gray-400"><span
|
||||
class="font-semibold">Click to upload</span> or drag and drop</p>
|
||||
<p class="text-xs text-gray-400">SVG, PNG, JPG or GIF (MAX.
|
||||
800x400px)</p>
|
||||
</div>
|
||||
<input id="dropzone-file" type="file" class="hidden" />
|
||||
</label>
|
||||
|
||||
</div>
|
||||
<div>
|
||||
<div hidden>
|
||||
<div class="flex items-center gap-x-3 whitespace-nowrap">
|
||||
<div id="progress-fake" class="flex w-full h-2 rounded-full overflow-hidden bg-gray-700"
|
||||
role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100">
|
||||
<div id="progress-fake"
|
||||
class="flex flex-col justify-center rounded-full overflow-hidden bg-teal-500 text-xs text-white text-center whitespace-nowrap transition duration-500">
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-6 text-end">
|
||||
<span id="progress-fake" class="text-sm text-white">Starting...</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="container"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/public/upload.js" />
|
||||
}
|
||||
}
|
||||
|
||||
templ Main(title string) {
|
||||
@content(title)
|
||||
}
|
53
view/user/user.templ
Normal file
53
view/user/user.templ
Normal file
@ -0,0 +1,53 @@
|
||||
package userView
|
||||
|
||||
import "github.com/fossyy/filekeeper/view/layout"
|
||||
|
||||
templ content(email string, username string, title string) {
|
||||
@layout.Base(title){
|
||||
<div class="bg-white overflow-hidden shadow rounded-lg border">
|
||||
<div class="px-4 py-5 sm:px-6">
|
||||
<h3 class="text-lg leading-6 font-medium text-gray-900">
|
||||
User Profile
|
||||
</h3>
|
||||
<p class="mt-1 max-w-2xl text-sm text-gray-500">
|
||||
This is some information about the user.
|
||||
</p>
|
||||
</div>
|
||||
<div class="border-t border-gray-200 px-4 py-5 sm:p-0">
|
||||
<dl class="sm:divide-y sm:divide-gray-200">
|
||||
<div class="py-3 sm:py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
||||
<dt class="text-sm font-medium text-gray-500">
|
||||
Full name
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">
|
||||
{ username }
|
||||
</dd>
|
||||
</div>
|
||||
<div class="py-3 sm:py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
||||
<dt class="text-sm font-medium text-gray-500">
|
||||
Email address
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">
|
||||
{ email }
|
||||
</dd>
|
||||
</div>
|
||||
<div class="py-3 sm:py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
||||
<dt class="text-sm font-medium text-gray-500">
|
||||
Password
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">
|
||||
ntah lah
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
<form action="/logout" method="get">
|
||||
<button type="submit" class="focus:outline-none text-white bg-red-700 hover:bg-red-800 focus:ring-4 focus:ring-red-300 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2 dark:bg-red-600 dark:hover:bg-red-700 dark:focus:ring-red-900">Logout</button>
|
||||
</form>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
templ Main(title string, email string, username string) {
|
||||
@content(email, username, title)
|
||||
}
|
Reference in New Issue
Block a user