2026-07-14 21:54:14 -05:00
const TELEGRAM_URL = "https://t.me/Onimai" ;
2026-08-24 10:06:19 -05:00
const GITEA_ISSUES_URL = "https://overlord.kyun.li/vxaboveground/overlord/issues/new" ;
2026-07-14 21:54:14 -05:00
let mounted = false ;
export function showOnboardingIfNeeded ( user ) {
if ( ! user ? . needsOnboarding || mounted ) return ;
mounted = true ;
const style = document . createElement ( "style" );
style . textContent = `
.account-onboarding { position: fixed; inset: 0; z-index: 10000; display: grid; place-items: center; padding: 1.25rem; background: rgba(2, 6, 23, .88); backdrop-filter: blur(10px); }
.account-onboarding__panel { width: min(100%, 42rem); overflow: hidden; border: 1px solid rgba(71, 85, 105, .8); border-radius: 1rem; background: #0f172a; color: #e2e8f0; box-shadow: 0 24px 80px rgba(0, 0, 0, .55); }
.account-onboarding__hero { padding: 2rem 2rem 1.25rem; text-align: center; background: radial-gradient(circle at top, rgba(14, 165, 233, .2), transparent 65%); }
.account-onboarding__icon { display: grid; place-items: center; width: 3.5rem; height: 3.5rem; margin: 0 auto 1rem; border: 1px solid rgba(56, 189, 248, .4); border-radius: .9rem; background: rgba(14, 165, 233, .12); color: #38bdf8; font-size: 1.5rem; }
.account-onboarding h1 { margin: 0; color: #f8fafc; font-size: 1.65rem; line-height: 1.2; font-weight: 700; }
.account-onboarding__intro { margin: .65rem auto 0; max-width: 33rem; color: #94a3b8; line-height: 1.55; }
.account-onboarding__progress { display: flex; align-items: center; justify-content: center; gap: .5rem; margin-top: 1.15rem; color: #64748b; font-size: .8rem; font-weight: 600; }
.account-onboarding__dot { width: .55rem; height: .55rem; border-radius: 999px; background: #334155; }
.account-onboarding__dot--active { background: #38bdf8; box-shadow: 0 0 0 4px rgba(56, 189, 248, .12); }
.account-onboarding__step { padding: .25rem 2rem 1.25rem; }
.account-onboarding__card { padding: 1.35rem; border: 1px solid #334155; border-radius: .85rem; background: rgba(30, 41, 59, .65); text-align: center; }
.account-onboarding__card h2 { margin: 0 0 .55rem; color: #f8fafc; font-size: 1.2rem; }
.account-onboarding__card p { margin: 0; color: #cbd5e1; line-height: 1.55; }
.account-onboarding__url-label { margin-top: 1.15rem; color: #94a3b8; font-size: .75rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; }
.account-onboarding__url { display: block; margin-top: .4rem; padding: .7rem .8rem; overflow-wrap: anywhere; border: 1px solid #475569; border-radius: .55rem; background: #020617; color: #7dd3fc; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: .88rem; text-decoration: underline; }
.account-onboarding__open { display: inline-flex; align-items: center; justify-content: center; gap: .5rem; margin-top: 1rem; padding: .65rem 1rem; border: 1px solid #0369a1; border-radius: .6rem; background: rgba(3, 105, 161, .18); color: #e0f2fe; font-weight: 600; text-decoration: none; transition: background .15s, border-color .15s; }
.account-onboarding__open:hover { border-color: #38bdf8; background: rgba(14, 165, 233, .28); }
.account-onboarding__footer { padding: .5rem 2rem 1.5rem; text-align: center; }
.account-onboarding__continue { width: 100%; padding: .75rem 1rem; border: 0; border-radius: .65rem; background: #0284c7; color: white; font: inherit; font-weight: 600; cursor: pointer; transition: background .15s; }
.account-onboarding__continue:hover { background: #0ea5e9; }
.account-onboarding__continue:disabled { cursor: wait; opacity: .65; }
.account-onboarding__error { min-height: 1.25rem; margin: .55rem 0 0; color: #fca5a5; font-size: .8rem; }
@media (max-width: 600px) { .account-onboarding__hero { padding: 1.5rem 1.25rem 1.1rem; } .account-onboarding__step { padding: .2rem 1.25rem 1rem; } .account-onboarding__footer { padding: .5rem 1.25rem 1.25rem; } }
` ;
const overlay = document . createElement ( "div" );
overlay . className = "account-onboarding" ;
overlay . setAttribute ( "role" , "dialog" );
overlay . setAttribute ( "aria-modal" , "true" );
overlay . setAttribute ( "aria-labelledby" , "account-onboarding-title" );
overlay . innerHTML = `
<section class="account-onboarding__panel">
<div class="account-onboarding__hero">
<div class="account-onboarding__icon"><i class="fa-solid fa-crown" aria-hidden="true"></i></div>
<h1 id="account-onboarding-title">Welcome to Overlord</h1>
<p class="account-onboarding__intro">Please review both support resources so you always know exactly where to go.</p>
<div class="account-onboarding__progress" aria-label="Onboarding progress">
<span class="account-onboarding__dot account-onboarding__dot--active"></span>
<span class="account-onboarding__progress-text">Step 1 of 2</span>
<span class="account-onboarding__dot"></span>
</div>
</div>
<div class="account-onboarding__step"></div>
<div class="account-onboarding__footer">
<button class="account-onboarding__continue" type="button">Confirm: I know where to get help</button>
<p class="account-onboarding__error" role="alert"></p>
</div>
</section>
` ;
document . head . appendChild ( style );
document . body . appendChild ( overlay );
document . body . style . overflow = "hidden" ;
const button = overlay . querySelector ( ".account-onboarding__continue" );
const error = overlay . querySelector ( ".account-onboarding__error" );
const stepContent = overlay . querySelector ( ".account-onboarding__step" );
const progressText = overlay . querySelector ( ".account-onboarding__progress-text" );
const progressDots = overlay . querySelectorAll ( ".account-onboarding__dot" );
let currentStep = 1 ;
const renderStep = () => {
if ( currentStep === 1 ) {
stepContent . innerHTML = `
<div class="account-onboarding__card">
<h2><i class="fa-brands fa-telegram" aria-hidden="true"></i> Need help? Use Telegram</h2>
<p><strong>This is the place to ask for help and talk with the community.</strong> Join the Telegram if you have questions, need assistance, or want project updates.</p>
<div class="account-onboarding__url-label">Full Telegram link</div>
<a class="account-onboarding__url" href=" ${ TELEGRAM_URL } " target="_blank" rel="noopener noreferrer"> ${ TELEGRAM_URL } </a>
<a class="account-onboarding__open" href=" ${ TELEGRAM_URL } " target="_blank" rel="noopener noreferrer"><i class="fa-brands fa-telegram" aria-hidden="true"></i> Open Telegram</a>
</div>
` ;
progressText . textContent = "Step 1 of 2" ;
progressDots [ 0 ]. classList . add ( "account-onboarding__dot--active" );
progressDots [ 1 ]. classList . remove ( "account-onboarding__dot--active" );
button . textContent = "Confirm: I know where to get help" ;
return ;
}
stepContent . innerHTML = `
<div class="account-onboarding__card">
2026-08-24 10:06:19 -05:00
<h2><i class="fa-solid fa-code-branch" aria-hidden="true"></i> Found a bug? Use Gitea Issues</h2>
<p><strong>This is the official place to report bugs.</strong> Create a Gitea issue with what happened, what you expected, and any useful screenshots or logs so the problem can be tracked and fixed.</p>
2026-07-14 21:54:14 -05:00
<div class="account-onboarding__url-label">Full bug report link</div>
2026-08-24 10:06:19 -05:00
<a class="account-onboarding__url" href=" ${ GITEA_ISSUES_URL } " target="_blank" rel="noopener noreferrer"> ${ GITEA_ISSUES_URL } </a>
<a class="account-onboarding__open" href=" ${ GITEA_ISSUES_URL } " target="_blank" rel="noopener noreferrer"><i class="fa-solid fa-code-branch" aria-hidden="true"></i> Create a Gitea issue</a>
2026-07-14 21:54:14 -05:00
</div>
` ;
progressText . textContent = "Step 2 of 2" ;
progressDots [ 0 ]. classList . remove ( "account-onboarding__dot--active" );
progressDots [ 1 ]. classList . add ( "account-onboarding__dot--active" );
button . textContent = "Confirm: I know where to report bugs" ;
};
renderStep ();
button ? . focus ();
button ? . addEventListener ( "click" , async () => {
if ( currentStep === 1 ) {
currentStep = 2 ;
renderStep ();
button . focus ();
return ;
}
button . disabled = true ;
error . textContent = "" ;
try {
const response = await fetch ( "/api/auth/onboarding/complete" , {
method : "POST" ,
credentials : "include" ,
2026-07-15 10:14:42 -05:00
cache : "no-store" ,
2026-07-14 21:54:14 -05:00
});
if ( ! response . ok ) throw new Error ( "Could not save your onboarding status." );
overlay . remove ();
style . remove ();
document . body . style . overflow = "" ;
} catch ( err ) {
error . textContent = err instanceof Error ? err . message : "Please try again." ;
button . disabled = false ;
button . focus ();
}
});
}