parent
24c262282e
commit
c06c236da5
23 changed files with 158 additions and 242 deletions
@ -0,0 +1,85 @@ |
||||
--- |
||||
import Icon from './AstroIcon.astro'; |
||||
|
||||
const { activePageId, activePageTitle } = Astro.props; |
||||
|
||||
export interface Props { |
||||
activePageId: string; |
||||
activePageTitle: string; |
||||
} |
||||
--- |
||||
|
||||
<div class='relative block mb-5 md:hidden p-4 border-b shadow-inner'> |
||||
<button |
||||
class='flex h-10 w-full items-center justify-between rounded-md border bg-white px-2 text-center font-medium text-gray-900' |
||||
id='settings-menu' |
||||
> |
||||
{activePageTitle} |
||||
<Icon icon='dropdown' /> |
||||
</button> |
||||
<ul |
||||
id='settings-menu-dropdown' |
||||
class='absolute mt-1 hidden left-0 right-0 space-y-1.5 bg-white p-2 shadow-lg z-10' |
||||
> |
||||
<li> |
||||
<a |
||||
href='/account/update-profile' |
||||
class=`block w-full rounded px-2 py-1.5 font-medium text-slate-900 hover:bg-slate-200 ${activePageId === 'profile' ? 'bg-slate-100' : ''}` |
||||
>Profile</a |
||||
> |
||||
</li> |
||||
<li> |
||||
<a |
||||
href='/account/update-password' |
||||
class=`block w-full rounded px-2 py-1.5 font-medium text-slate-900 hover:bg-slate-200 ${activePageId === 'change-password' ? 'bg-slate-100' : ''}` |
||||
>Change password</a |
||||
> |
||||
</li> |
||||
</ul> |
||||
</div> |
||||
|
||||
<div class='container flex min-h-screen items-stretch'> |
||||
<!-- Start Desktop Sidebar --> |
||||
<aside class='hidden w-56 border-r border-slate-200 py-10 pr-5 md:block'> |
||||
<nav> |
||||
<ul class='space-y-1'> |
||||
<li> |
||||
<a |
||||
href='/account/update-profile' |
||||
class=`block w-full rounded px-2 py-1.5 font-regular text-slate-900 hover:bg-slate-100 ${activePageId === 'profile' ? 'bg-slate-100' : ''}` |
||||
> |
||||
Profile |
||||
</a> |
||||
</li> |
||||
<li> |
||||
<a |
||||
href='/account/update-password' |
||||
class=`block w-full rounded px-2 py-1.5 font-regular text-slate-900 hover:bg-slate-100 ${activePageId === 'change-password' ? 'bg-slate-100' : ''}` |
||||
> |
||||
Security |
||||
</a> |
||||
</li> |
||||
</ul> |
||||
</nav> |
||||
</aside> |
||||
<!-- /End Desktop Sidebar --> |
||||
|
||||
<div class='grow px-0 py-0 md:px-10 md:py-10'> |
||||
<slot /> |
||||
</div> |
||||
</div> |
||||
|
||||
<script> |
||||
const menuButton = document.getElementById('settings-menu'); |
||||
const menuDropdown = document.getElementById('settings-menu-dropdown'); |
||||
|
||||
menuButton?.addEventListener('click', () => { |
||||
menuDropdown?.classList.toggle('hidden'); |
||||
}); |
||||
|
||||
document.addEventListener('click', (e) => { |
||||
if (!menuButton?.contains(e.target as Node)) { |
||||
menuDropdown?.classList.add('hidden'); |
||||
} |
||||
}); |
||||
</script> |
@ -1,5 +0,0 @@ |
||||
--- |
||||
--- |
||||
|
||||
<div class='recaptcha-field mb-2'></div> |
||||
<input type='hidden' name='g-recaptcha-response' class='recaptcha-response' /> |
@ -1,36 +0,0 @@ |
||||
--- |
||||
|
||||
--- |
||||
|
||||
<script src='./captcha.js'></script> |
||||
|
||||
<script is:inline> |
||||
window.onCaptchaLoad = function () { |
||||
if (!window.grecaptcha) { |
||||
console.warn('window.grecaptcha is not defined'); |
||||
return; |
||||
} |
||||
|
||||
const recaptchaFields = document.querySelectorAll('.recaptcha-field'); |
||||
|
||||
// render recaptcha on fields |
||||
recaptchaFields.forEach((field) => { |
||||
// If captcha already rendered for this field |
||||
if (field.hasAttribute('data-recaptcha-id')) { |
||||
return; |
||||
} |
||||
|
||||
const renderedId = window.grecaptcha.render(field, { |
||||
sitekey: '6Ldn2YsjAAAAABlUxNxukAuDAUIuZIhO0hRVxzJW', |
||||
}); |
||||
|
||||
field.setAttribute('data-recaptcha-id', renderedId); |
||||
}); |
||||
}; |
||||
</script> |
||||
|
||||
<script |
||||
src='https://www.google.com/recaptcha/api.js?onload=onCaptchaLoad&render=explicit' |
||||
async |
||||
defer |
||||
></script> |
@ -1,49 +0,0 @@ |
||||
class Captcha { |
||||
constructor() { |
||||
this.onDOMLoaded = this.onDOMLoaded.bind(this); |
||||
this.bindValidation = this.bindValidation.bind(this); |
||||
this.validateCaptchaBeforeSubmit = |
||||
this.validateCaptchaBeforeSubmit.bind(this); |
||||
} |
||||
|
||||
validateCaptchaBeforeSubmit(e) { |
||||
const target = e.target; |
||||
const captchaField = target.querySelector('.recaptcha-field'); |
||||
|
||||
if (captchaField) { |
||||
const captchaId = captchaField.dataset.recaptchaId; |
||||
const captchaResponse = window.grecaptcha.getResponse(captchaId); |
||||
|
||||
// If valid captcha is not present, prevent form submission
|
||||
if (!captchaResponse) { |
||||
e.preventDefault(); |
||||
alert('Please verify that you are human first'); |
||||
return false; |
||||
} |
||||
|
||||
target.querySelector('.recaptcha-response').value = captchaResponse; |
||||
} |
||||
|
||||
target.closest('.popup').classList.add('hidden'); |
||||
return true; |
||||
} |
||||
|
||||
bindValidation() { |
||||
const forms = document.querySelectorAll('[captcha-form]'); |
||||
|
||||
forms.forEach((form) => { |
||||
form.addEventListener('submit', this.validateCaptchaBeforeSubmit); |
||||
}); |
||||
} |
||||
|
||||
onDOMLoaded() { |
||||
this.bindValidation(); |
||||
} |
||||
|
||||
init() { |
||||
window.addEventListener('DOMContentLoaded', this.onDOMLoaded); |
||||
} |
||||
} |
||||
|
||||
const captcha = new Captcha(); |
||||
captcha.init(); |
@ -1,81 +0,0 @@ |
||||
--- |
||||
import Icon from '../AstroIcon.astro'; |
||||
const { pageUrl, name } = Astro.props; |
||||
|
||||
export interface Props { |
||||
pageUrl: string; |
||||
name: string; |
||||
} |
||||
--- |
||||
|
||||
<div |
||||
class='container flex min-h-[calc(100vh-37px-70px)] items-stretch sm:min-h-[calc(100vh-37px-96px)]' |
||||
> |
||||
<aside class='hidden w-56 border-r border-slate-200 py-10 pr-5 md:block'> |
||||
<nav> |
||||
<ul class='space-y-1'> |
||||
<li> |
||||
<a |
||||
href='/settings/update-profile' |
||||
class=`block w-full rounded px-2 py-1.5 font-regular text-slate-900 hover:bg-slate-100 ${pageUrl === 'profile' ? 'bg-slate-100' : ''}` |
||||
>Profile</a |
||||
> |
||||
</li> |
||||
<li> |
||||
<a |
||||
href='/settings/update-password' |
||||
class=`block w-full rounded px-2 py-1.5 font-regular text-slate-900 hover:bg-slate-100 ${pageUrl === 'change-password' ? 'bg-slate-100' : ''}` |
||||
>Security</a |
||||
> |
||||
</li> |
||||
</ul> |
||||
</nav> |
||||
</aside> |
||||
<div class='grow py-10 pl-0 md:p-10 md:pr-0'> |
||||
<div class='relative mb-5 md:hidden'> |
||||
<button |
||||
class='flex h-10 w-full items-center justify-between rounded-md bg-slate-800 px-2 text-center font-medium text-slate-100' |
||||
id='settings-menu' |
||||
> |
||||
{name} |
||||
<Icon icon='dropdown' /> |
||||
</button> |
||||
<ul |
||||
id='settings-menu-dropdown' |
||||
class='absolute mt-1 hidden w-full space-y-1.5 rounded-md bg-white p-2 shadow-lg' |
||||
> |
||||
<li> |
||||
<a |
||||
href='/settings/update-profile' |
||||
class=`block w-full rounded px-2 py-1.5 font-medium text-slate-900 hover:bg-slate-200 ${pageUrl === 'profile' ? 'bg-slate-100' : ''}` |
||||
>Profile</a |
||||
> |
||||
</li> |
||||
<li> |
||||
<a |
||||
href='/settings/update-password' |
||||
class=`block w-full rounded px-2 py-1.5 font-medium text-slate-900 hover:bg-slate-200 ${pageUrl === 'change-password' ? 'bg-slate-100' : ''}` |
||||
>Change password</a |
||||
> |
||||
</li> |
||||
</ul> |
||||
</div> |
||||
|
||||
<slot /> |
||||
</div> |
||||
</div> |
||||
|
||||
<script> |
||||
const menuButton = document.getElementById('settings-menu'); |
||||
const menuDropdown = document.getElementById('settings-menu-dropdown'); |
||||
|
||||
menuButton?.addEventListener('click', () => { |
||||
menuDropdown?.classList.toggle('hidden'); |
||||
}); |
||||
|
||||
document.addEventListener('click', (e) => { |
||||
if (!menuButton?.contains(e.target as Node)) { |
||||
menuDropdown?.classList.add('hidden'); |
||||
} |
||||
}); |
||||
</script> |
@ -0,0 +1,16 @@ |
||||
--- |
||||
import AccountSidebar from '../../components/AccountSidebar.astro'; |
||||
import UpdatePasswordForm from '../../components/UpdatePassword/UpdatePasswordForm'; |
||||
import AccountLayout from '../../layouts/AccountLayout.astro'; |
||||
--- |
||||
|
||||
<AccountLayout |
||||
title='Change Password' |
||||
description='' |
||||
noIndex={true} |
||||
initialLoadingMessage={'Loading profile'} |
||||
> |
||||
<AccountSidebar activePageId='change-password' activePageTitle='Change Password'> |
||||
<UpdatePasswordForm client:load /> |
||||
</AccountSidebar> |
||||
</AccountLayout> |
@ -0,0 +1,15 @@ |
||||
--- |
||||
import AccountSidebar from '../../components/AccountSidebar.astro'; |
||||
import { UpdateProfileForm } from '../../components/UpdateProfile/UpdateProfileForm'; |
||||
import AccountLayout from '../../layouts/AccountLayout.astro'; |
||||
--- |
||||
|
||||
<AccountLayout |
||||
title='Update Profile' |
||||
noIndex={true} |
||||
initialLoadingMessage={'Loading profile'} |
||||
> |
||||
<AccountSidebar activePageId='profile' activePageTitle='Profile'> |
||||
<UpdateProfileForm client:load /> |
||||
</AccountSidebar> |
||||
</AccountLayout> |
@ -1,16 +0,0 @@ |
||||
--- |
||||
import SettingSidebar from '../../components/Setting/SettingSidebar.astro'; |
||||
import UpdatePasswordForm from '../../components/Setting/UpdatePasswordForm'; |
||||
import SettingLayout from '../../layouts/SettingLayout.astro'; |
||||
--- |
||||
|
||||
<SettingLayout |
||||
title='Change Password' |
||||
description='' |
||||
noIndex={true} |
||||
initialLoadingMessage={'Loading profile'} |
||||
> |
||||
<SettingSidebar pageUrl='change-password' name='Change Password'> |
||||
<UpdatePasswordForm client:load /> |
||||
</SettingSidebar> |
||||
</SettingLayout> |
@ -1,15 +0,0 @@ |
||||
--- |
||||
import SettingSidebar from '../../components/Setting/SettingSidebar.astro'; |
||||
import { UpdateProfileForm } from '../../components/Setting/UpdateProfileForm'; |
||||
import SettingLayout from '../../layouts/SettingLayout.astro'; |
||||
--- |
||||
|
||||
<SettingLayout |
||||
title='Update Profile' |
||||
noIndex={true} |
||||
initialLoadingMessage={'Loading profile'} |
||||
> |
||||
<SettingSidebar pageUrl='profile' name='Profile'> |
||||
<UpdateProfileForm client:load /> |
||||
</SettingSidebar> |
||||
</SettingLayout> |
@ -1,10 +1,10 @@ |
||||
--- |
||||
import { VerificationEmailMessage } from '../components/AuthenticationFlow/VerificationEmailMessage'; |
||||
import SettingLayout from '../layouts/SettingLayout.astro'; |
||||
import AccountLayout from '../layouts/AccountLayout.astro'; |
||||
--- |
||||
|
||||
<SettingLayout title='Verify Email' noIndex={true}> |
||||
<AccountLayout title='Verify Email' noIndex={true}> |
||||
<section class='container py-8 sm:py-20'> |
||||
<VerificationEmailMessage client:load /> |
||||
</section> |
||||
</SettingLayout> |
||||
</AccountLayout> |
||||
|
@ -1,10 +1,10 @@ |
||||
--- |
||||
import { TriggerVerifyAccount } from '../components/AuthenticationFlow/TriggerVerifyAccount'; |
||||
import SettingLayout from '../layouts/SettingLayout.astro'; |
||||
import AccountLayout from '../layouts/AccountLayout.astro'; |
||||
--- |
||||
|
||||
<SettingLayout title='Verify account' noIndex={true}> |
||||
<AccountLayout title='Verify account' noIndex={true}> |
||||
<div class='container py-16'> |
||||
<TriggerVerifyAccount client:load /> |
||||
</div> |
||||
</SettingLayout> |
||||
</AccountLayout> |
||||
|
Loading…
Reference in new issue