register.vue
1 <template> 2 <main> 3 <div class="branding"> 4 <h1 class="title"> 5 <svg 6 width="124" 7 height="28" 8 viewBox="0 0 124 28" 9 fill="none" 10 xmlns="http://www.w3.org/2000/svg"> 11 <defs> 12 <clipPath id="clip_path_1"> 13 <rect width="124" height="28" /> 14 </clipPath> 15 </defs> 16 <path 17 d="M29.32 -1.90735e-06L1.32 -1.90735e-06L1.32 5.6L18.12 5.6L1.32 28L29.32 28L29.32 22.4L12.5197 22.4L29.32 -1.90735e-06ZM60.44 5.6L60.44 -1.90735e-06L32.44 -1.90735e-06L32.44 5.6L43.64 5.6L43.64 22.4L32.44 22.4L32.44 28L60.44 28L60.44 22.4L49.24 22.4L49.24 5.6L60.44 5.6ZM92.04 5.6L92.04 -1.90735e-06L64.04 -1.90735e-06L64.04 5.6L75.24 5.6L75.24 22.4L64.04 22.4L64.04 28L92.04 28L92.04 22.4L80.84 22.4L80.84 5.6L92.04 5.6ZM94.72 -1.90735e-06L94.72 5.6L105.92 5.6L105.92 28L111.52 28L111.52 5.6L122.72 5.6L122.72 -1.90735e-06L94.72 -1.90735e-06Z" 18 fill="#E6E6E6" 19 clip-path="url(#clip_path_1)" /> 20 </svg> 21 </h1> 22 <p class="description"> 23 Please create your account or 24 <NuxtLink to="/login"><u>Login</u></NuxtLink> 25 </p> 26 </div> 27 <form 28 class="form" 29 @submit.prevent="register" 30 autocomplete="on" 31 data-form-type="register"> 32 <UiInput 33 v-model="email" 34 placeholder="Email" 35 type="text" 36 :icon="LucideMail" 37 @focus="isInputFocused = true" 38 @blur="isInputFocused = false" /> 39 <UiInput 40 v-model="password" 41 placeholder="Password" 42 type="password" 43 :icon="LucideKeyRound" 44 @focus="isInputFocused = true" 45 @blur="isInputFocused = false" /> 46 </form> 47 <div class="buttons"> 48 <UiButton text="Register" keyName="enter" @click="register" /> 49 <UiButton text="Register with Github" keyName="g" @click="githubAuth" /> 50 </div> 51 </main> 52 </template> 53 54 <script setup lang="ts"> 55 import { LucideKeyRound, LucideMail } from "lucide-vue-next"; 56 import { Key } from "@waradu/keyboard"; 57 58 const error = ref(""); 59 const email = ref(""); 60 const password = ref(""); 61 const toast = useToast(); 62 const isInputFocused = ref(false); 63 64 async function register() { 65 try { 66 const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone; 67 68 await $fetch("/api/auth/register", { 69 method: "POST", 70 body: { 71 email: email.value, 72 password: password.value, 73 timezone, 74 }, 75 }); 76 await navigateTo("/"); 77 } catch (e: any) { 78 error.value = e.data?.message || "Register failed"; 79 toast.error(error.value); 80 } 81 } 82 83 async function githubAuth() { 84 window.location.href = "/api/auth/github"; 85 } 86 87 useKeybind([Key.G], async () => { 88 if (isInputFocused.value) return; 89 await githubAuth(); 90 }); 91 92 useKeybind( 93 [Key.Enter], 94 async () => { 95 await register(); 96 }, 97 { prevent: true } 98 ); 99 100 useSeoMeta({ 101 title: "Register - Ziit", 102 description: "Create your Ziit account to start tracking your coding time", 103 ogTitle: "Register - Ziit", 104 ogDescription: "Create your Ziit account to start tracking your coding time", 105 ogImage: "https://ziit.app/logo.webp", 106 ogUrl: "https://ziit.app/register", 107 ogSiteName: "Ziit", 108 twitterTitle: "Register - Ziit", 109 twitterDescription: 110 "Create your Ziit account to start tracking your coding time", 111 twitterImage: "https://ziit.app/logo.webp", 112 twitterCard: "summary", 113 twitterCreator: "@pandadev_", 114 twitterSite: "@pandadev_", 115 author: "PandaDEV", 116 }); 117 118 useHead({ 119 htmlAttrs: { lang: "en" }, 120 link: [ 121 { 122 rel: "canonical", 123 href: "https://ziit.app/register", 124 }, 125 { 126 rel: "icon", 127 type: "image/ico", 128 href: "/favicon.ico", 129 }, 130 ], 131 script: [ 132 { 133 type: "application/ld+json", 134 innerHTML: JSON.stringify({ 135 "@context": "https://schema.org", 136 "@type": "WebPage", 137 name: "Register - Ziit", 138 url: "https://ziit.app/register", 139 }), 140 }, 141 ], 142 }); 143 </script> 144 145 <style lang="scss"> 146 @use "~~/styles/login.scss"; 147 </style>