mirror of
https://github.com/fleetdm/fleet
synced 2026-05-24 01:18:42 +00:00
Website: Add testimonials to /register page (#20394)
Closes: #20074 Changes: - Added personalized testimonials to the /register page.
This commit is contained in:
parent
36ca428b17
commit
be919835e2
4 changed files with 232 additions and 67 deletions
|
|
@ -27,6 +27,7 @@ parasails.registerPage('signup', {
|
|||
// For redirecting users coming from the "Get your license" link to the license dispenser.
|
||||
loginSlug: '/login',
|
||||
pageToRedirectToAfterRegistration: '/start',
|
||||
primaryBuyingSituation: undefined
|
||||
},
|
||||
|
||||
// ╦ ╦╔═╗╔═╗╔═╗╦ ╦╔═╗╦ ╔═╗
|
||||
|
|
|
|||
129
website/assets/styles/pages/entrance/signup.less
vendored
129
website/assets/styles/pages/entrance/signup.less
vendored
|
|
@ -1,34 +1,74 @@
|
|||
#signup {
|
||||
padding-top: 80px;
|
||||
h1 {
|
||||
font-size: 28px;
|
||||
line-height: 38px;
|
||||
font-size: 32px;
|
||||
line-height: 120%;
|
||||
}
|
||||
a {
|
||||
line-height: 150%;
|
||||
color: @core-fleet-black-75;
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 2px;
|
||||
}
|
||||
[purpose='page-heading'] {
|
||||
padding-left: 30px;
|
||||
padding-right: 30px;
|
||||
text-align: center;
|
||||
margin-bottom: 40px;
|
||||
p {
|
||||
line-height: 150%;
|
||||
}
|
||||
[purpose='page-container'] {
|
||||
padding: 64px 128px 64px 128px;
|
||||
max-width: 1200px;
|
||||
}
|
||||
|
||||
[purpose='login-link'] {
|
||||
margin-bottom: 4px;
|
||||
a {
|
||||
float: right;
|
||||
[purpose='page-heading'] {
|
||||
text-align: left;
|
||||
margin-bottom: 48px;
|
||||
}
|
||||
|
||||
[purpose='quote-and-logos'] {
|
||||
max-width: 310px;
|
||||
}
|
||||
[purpose='quote'] {
|
||||
margin-top: 8px;
|
||||
}
|
||||
[purpose='quote-text'] {
|
||||
font-size: 14px;
|
||||
line-height: 150%;
|
||||
font-style: italic;
|
||||
}
|
||||
[purpose='quote-author-info'] {
|
||||
display: inline-flex;
|
||||
padding: 4px 16px 4px 4px;
|
||||
border-radius: 28px;
|
||||
width: fit-content;
|
||||
margin-top: 8px;
|
||||
margin-bottom: 48px;
|
||||
[purpose='job-title'] {
|
||||
color: @core-fleet-black-75;
|
||||
text-decoration: underline;
|
||||
font-size: 14px;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
line-height: 18px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
[purpose='name'] {
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
line-height: 18px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
[purpose='profile-picture'] {
|
||||
margin-right: 16px;
|
||||
img {
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
}
|
||||
}
|
||||
}
|
||||
[purpose='logos'] {
|
||||
max-width: 310px;
|
||||
}
|
||||
[purpose='signup-form'] {
|
||||
width: 528px;
|
||||
}
|
||||
[purpose='customer-portal-form'] {
|
||||
max-width: 560px;
|
||||
border-radius: 16px;
|
||||
margin-bottom: 40px;
|
||||
padding: 20px 32px 32px 32px;
|
||||
label {
|
||||
color: @core-fleet-black;
|
||||
|
|
@ -57,6 +97,19 @@
|
|||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
.small {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
[purpose='login-link'] {
|
||||
margin-bottom: 4px;
|
||||
a {
|
||||
float: right;
|
||||
color: @core-fleet-black-75;
|
||||
text-decoration: underline;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
[purpose='submit-button'] {
|
||||
|
|
@ -78,21 +131,61 @@
|
|||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
@media (max-width: 1200px) {
|
||||
[purpose='page-container'] {
|
||||
padding: 64px;
|
||||
}
|
||||
}
|
||||
@media (max-width: 991px) {
|
||||
[purpose='signup-form'] {
|
||||
max-width: 528px;
|
||||
}
|
||||
[purpose='quote-and-logos'] {
|
||||
max-width: 528px;
|
||||
margin-top: 48px;
|
||||
}
|
||||
[purpose='logos'] {
|
||||
max-width: 528px;
|
||||
}
|
||||
[purpose='page-heading'] {
|
||||
text-align: center;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-bottom: 48px;
|
||||
max-width: 528px;
|
||||
}
|
||||
[purpose='page-container'] {
|
||||
padding: 64px 32px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
padding-top: 60px;
|
||||
[purpose='customer-portal-form'] {
|
||||
max-width: unset;
|
||||
}
|
||||
[purpose='signup-form'] {
|
||||
width: 100%;
|
||||
}
|
||||
[purpose='quote-and-logos'] {
|
||||
width: 100%;
|
||||
}
|
||||
[purpose='logos'] {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 576px) {
|
||||
padding-top: 40px;
|
||||
[purpose='page-heading'] {
|
||||
padding-left: 0px;
|
||||
padding-right: 0px;
|
||||
}
|
||||
[purpose='page-container'] {
|
||||
padding: 48px 24px;
|
||||
}
|
||||
[purpose='login-link'] {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
[purpose='customer-portal-form'] {
|
||||
.card-body {
|
||||
padding: 1.5em 1em;
|
||||
|
|
|
|||
2
website/config/routes.js
vendored
2
website/config/routes.js
vendored
|
|
@ -113,7 +113,6 @@ module.exports.routes = {
|
|||
'GET /register': {
|
||||
action: 'entrance/view-signup',
|
||||
locals: {
|
||||
hideHeaderLinks: true,
|
||||
hideFooterLinks: true,
|
||||
pageTitleForMeta: 'Sign up | Fleet',
|
||||
pageDescriptionForMeta: 'Sign up for a Fleet account.',
|
||||
|
|
@ -122,7 +121,6 @@ module.exports.routes = {
|
|||
'GET /login': {
|
||||
action: 'entrance/view-login',
|
||||
locals: {
|
||||
hideHeaderLinks: true,
|
||||
hideFooterLinks: true,
|
||||
pageTitleForMeta: 'Log in | Fleet',
|
||||
pageDescriptionForMeta: 'Log in to Fleet.',
|
||||
|
|
|
|||
167
website/views/pages/entrance/signup.ejs
vendored
167
website/views/pages/entrance/signup.ejs
vendored
|
|
@ -1,62 +1,135 @@
|
|||
<div id="signup" v-cloak>
|
||||
<div style="max-width: 560px;" class="container-fluid pb-5 px-lg-0 px-3">
|
||||
<div purpose="page-container" class="container">
|
||||
<div purpose="page-heading">
|
||||
<h1>Welcome to Fleet</h1>
|
||||
<p class="mb-0">We just need a few details in order to get started.</p>
|
||||
</div>
|
||||
<div purpose="customer-portal-form" class="card card-body">
|
||||
<div purpose="login-link">
|
||||
<a :href="loginSlug">I have an account</a>
|
||||
<div purpose="form-container" class="d-flex flex-lg-row flex-column justify-content-between align-items-start">
|
||||
<div purpose="signup-form" class="mx-auto mx-lg-0">
|
||||
<div purpose="customer-portal-form" class="card card-body">
|
||||
<div purpose="login-link">
|
||||
<a :href="loginSlug">I have an account</a>
|
||||
</div>
|
||||
<ajax-form action="signup" class="self-service-register" :syncing.sync="syncing" :cloud-error.sync="cloudError" :form-errors.sync="formErrors" :form-data="formData" :form-rules="formRules" @submitted="submittedSignUpForm()">
|
||||
<div class="form-group">
|
||||
<label for="email-address">Work email *</label>
|
||||
<input class="form-control" id="email-address" :class="[formErrors.emailAddress ? 'is-invalid' : '']" v-model.trim="formData.emailAddress" @input="typeClearOneFormError('emailAddress')">
|
||||
<div class="invalid-feedback" v-if="formErrors.emailAddress" focus-first>This doesn’t appear to be a valid email address</div>
|
||||
</div>
|
||||
<div v-show="formData.emailAddress || showFullForm">
|
||||
<div class="form-group">
|
||||
<label for="password">Choose a password *</label>
|
||||
<input class="form-control" id="password" type="password" :class="[formErrors.password ? 'is-invalid' : '']" v-model.trim="formData.password" autocomplete="new-password" @input="typeClearOneFormError('password')">
|
||||
<div class="invalid-feedback" v-if="formErrors.password === 'minLength'">Password too short.</div>
|
||||
<div class="invalid-feedback" v-if="formErrors.password === 'required'">Please enter a password.</div>
|
||||
<p class="mt-2 small"> Minimum length is 8 characters</p>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="organization">Organization *</label>
|
||||
<input class="form-control" id="organization" type="text" :class="[formErrors.organization ? 'is-invalid' : '']" v-model.trim="formData.organization" @input="typeClearOneFormError('organization')">
|
||||
<div class="invalid-feedback" v-if="formErrors.organization">Please enter the name of your organization.</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12 col-sm-6 pr-sm-2">
|
||||
<div class="form-group">
|
||||
<label for="first-name">First name *</label>
|
||||
<input class="form-control" id="first-name" type="text" :class="[formErrors.firstName ? 'is-invalid' : '']" v-model.trim="formData.firstName" autocomplete="first-name" @input="typeClearOneFormError('firstName')">
|
||||
<div class="invalid-feedback" v-if="formErrors.firstName">Please enter your first name.</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6 pl-sm-2">
|
||||
<div class="form-group">
|
||||
<label for="last-name">Last name *</label>
|
||||
<input class="form-control" id="last-name" type="text" :class="[formErrors.lastName ? 'is-invalid' : '']" v-model.trim="formData.lastName" autocomplete="last-name" @input="typeClearOneFormError('lastName')">
|
||||
<div class="invalid-feedback" v-if="formErrors.lastName">Please enter your last name.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<cloud-error v-if="cloudError==='emailAlreadyInUse'">
|
||||
<p>This email is already linked to a Fleet account.<br> Please <a href="/login">sign in</a> with your email and password.</p>
|
||||
</cloud-error>
|
||||
<cloud-error v-else-if="cloudError === 'invalidEmailDomain'">
|
||||
<p>Please enter your work or school email address</p>
|
||||
</cloud-error>
|
||||
<cloud-error purpose="cloud-error" v-else-if="cloudError"></cloud-error>
|
||||
<p class="small">By signing up you agree to our <a href="/legal/privacy">privacy policy</a> and <a href="/terms">terms of service</a>.</p>
|
||||
<ajax-button purpose="submit-button" spinner="true" type="submit" :syncing="syncing" class="btn btn-block btn-lg btn-primary mt-4" v-if="!cloudError">Agree and continue</ajax-button>
|
||||
<ajax-button purpose="submit-button" type="button" :syncing="syncing" class="btn btn-block btn-lg btn-primary mt-4" v-if="cloudError" @click="clickResetForm()">Try again</ajax-button>
|
||||
</ajax-form>
|
||||
</div>
|
||||
</div>
|
||||
<ajax-form action="signup" class="self-service-register" :syncing.sync="syncing" :cloud-error.sync="cloudError" :form-errors.sync="formErrors" :form-data="formData" :form-rules="formRules" @submitted="submittedSignUpForm()">
|
||||
<div class="form-group">
|
||||
<label for="email-address">Work email *</label>
|
||||
<input class="form-control" id="email-address" :class="[formErrors.emailAddress ? 'is-invalid' : '']" v-model.trim="formData.emailAddress" @input="typeClearOneFormError('emailAddress')">
|
||||
<div class="invalid-feedback" v-if="formErrors.emailAddress" focus-first>This doesn’t appear to be a valid email address</div>
|
||||
</div>
|
||||
<div v-show="formData.emailAddress || showFullForm">
|
||||
<div class="form-group">
|
||||
<label for="password">Choose a password *</label>
|
||||
<input class="form-control" id="password" type="password" :class="[formErrors.password ? 'is-invalid' : '']" v-model.trim="formData.password" autocomplete="new-password" @input="typeClearOneFormError('password')">
|
||||
<div class="invalid-feedback" v-if="formErrors.password === 'minLength'">Password too short.</div>
|
||||
<div class="invalid-feedback" v-if="formErrors.password === 'required'">Please enter a password.</div>
|
||||
<p class="mt-2"> Minimum length is 8 characters</p>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="organization">Organization *</label>
|
||||
<input class="form-control" id="organization" type="text" :class="[formErrors.organization ? 'is-invalid' : '']" v-model.trim="formData.organization" @input="typeClearOneFormError('organization')">
|
||||
<div class="invalid-feedback" v-if="formErrors.organization">Please enter the name of your organization.</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12 col-sm-6 pr-sm-2">
|
||||
<div class="form-group">
|
||||
<label for="first-name">First name *</label>
|
||||
<input class="form-control" id="first-name" type="text" :class="[formErrors.firstName ? 'is-invalid' : '']" v-model.trim="formData.firstName" autocomplete="first-name" @input="typeClearOneFormError('firstName')">
|
||||
<div class="invalid-feedback" v-if="formErrors.firstName">Please enter your first name.</div>
|
||||
<div purpose="quote-and-logos" class="mx-auto mx-lg-0">
|
||||
<% if(typeof primaryBuyingSituation === 'undefined' || ['mdm'].includes(primaryBuyingSituation)) { %>
|
||||
<div purpose="quote">
|
||||
<img alt="an opening quotation mark" style="width:20px; margin-bottom: 16px;" src="/images/icon-quote-21x17@2x.png">
|
||||
<p purpose="quote-text">
|
||||
Exciting. This is a team that listens to feedback.
|
||||
</p>
|
||||
<div purpose="quote-author-info" class="d-flex flex-row align-items-center">
|
||||
<div purpose="profile-picture">
|
||||
<img alt="Erik Gomez" src="/images/testimonial-author-erik-gomez-48x48@2x.png">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6 pl-sm-2">
|
||||
<div class="form-group">
|
||||
<label for="last-name">Last name *</label>
|
||||
<input class="form-control" id="last-name" type="text" :class="[formErrors.lastName ? 'is-invalid' : '']" v-model.trim="formData.lastName" autocomplete="last-name" @input="typeClearOneFormError('lastName')">
|
||||
<div class="invalid-feedback" v-if="formErrors.lastName">Please enter your last name.</div>
|
||||
<div class="d-flex flex-column align-self-top">
|
||||
<p purpose="name" class="font-weight-bold m-0">Erik Gomez</p>
|
||||
<p purpose="job-title" class="m-0">Staff Client Platform Engineer</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% } else if (['eo-it'].includes(primaryBuyingSituation)) { %>
|
||||
<div purpose="quote">
|
||||
<img alt="an opening quotation mark" style="width:20px; margin-bottom: 16px;" src="/images/icon-quote-21x17@2x.png">
|
||||
<p purpose="quote-text">
|
||||
When we look at vendors, we look for ones that are very receptive to feedback, where you’re just part of the family, I guess. Fleet’s really good at that.
|
||||
</p>
|
||||
<div purpose="quote-author-info" class="d-flex flex-row align-items-center">
|
||||
<div purpose="profile-picture">
|
||||
<img alt="Harrison Ravazzolo" src="/images/testimonial-author-harrison-ravazzolo-48x48@2x.png">
|
||||
</div>
|
||||
<div class="d-flex flex-column align-self-top">
|
||||
<p purpose="name" class="font-weight-bold m-0">Harrison Ravazzolo</p>
|
||||
<p purpose="job-title" class="m-0">Lead platform and identity engineer</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% } else if (['eo-security'].includes(primaryBuyingSituation)) { %>
|
||||
<div purpose="quote">
|
||||
<img alt="an opening quotation mark" style="width:20px; margin-bottom: 16px;" src="/images/icon-quote-21x17@2x.png">
|
||||
<p purpose="quote-text">
|
||||
Something I really appreciate about working with you guys is that it doesn't feel like I'm talking to a vendor. It actually feels like I'm talking to my team, and I really appreciate it.
|
||||
</p>
|
||||
<div purpose="quote-author-info" class="d-flex flex-row align-items-center">
|
||||
<div purpose="profile-picture">
|
||||
<img alt="Chandra Majumdar" src="/images/testimonial-author-chandra-majumdar-48x48@2x.png">
|
||||
</div>
|
||||
<div class="d-flex flex-column align-self-top">
|
||||
<p purpose="name" class="font-weight-bold m-0">Chandra Majumdar</p>
|
||||
<p purpose="job-title" class="m-0">Partner - Cyber and Strategic Risk</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% } else if (['vm'].includes(primaryBuyingSituation)) { %>
|
||||
<div purpose="quote">
|
||||
<img alt="an opening quotation mark" style="width:20px; margin-bottom: 16px;" src="/images/icon-quote-21x17@2x.png">
|
||||
<p purpose="quote-text">
|
||||
The visibility down into the assets covered by the agent is phenomenal. Fleet has become the central source for a lot of things.
|
||||
</p>
|
||||
<div purpose="quote-author-info" class="d-flex flex-row align-items-center">
|
||||
<div purpose="profile-picture">
|
||||
<img alt="Andre Shields" src="/images/testimonial-author-andre-shields-48x48@2x.png">
|
||||
</div>
|
||||
<div class="d-flex flex-column align-self-top">
|
||||
<p purpose="name" class="font-weight-bold m-0">Andre Shields</p>
|
||||
<p purpose="job-title" class="m-0">Staff Cybersecurity Engineer, Vulnerability Management</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% } %>
|
||||
<div purpose="logos" class="flex-column flex-wrap align-items-center w-100">
|
||||
<logo-carousel></logo-carousel>
|
||||
</div>
|
||||
<cloud-error v-if="cloudError==='emailAlreadyInUse'">
|
||||
<p>This email is already linked to a Fleet account.<br> Please <a href="/login">sign in</a> with your email and password.</p>
|
||||
</cloud-error>
|
||||
<cloud-error v-else-if="cloudError === 'invalidEmailDomain'">
|
||||
<p>Please enter your work or school email address</p>
|
||||
</cloud-error>
|
||||
<cloud-error purpose="cloud-error" v-else-if="cloudError"></cloud-error>
|
||||
<p class="small">By signing up you agree to our <a href="/legal/privacy">privacy policy</a> and <a href="/terms">terms of service</a>.</p>
|
||||
<ajax-button purpose="submit-button" spinner="true" type="submit" :syncing="syncing" class="btn btn-block btn-lg btn-primary mt-4" v-if="!cloudError">Agree and continue</ajax-button>
|
||||
<ajax-button purpose="submit-button" type="button" :syncing="syncing" class="btn btn-block btn-lg btn-primary mt-4" v-if="cloudError" @click="clickResetForm()">Try again</ajax-button>
|
||||
</ajax-form>
|
||||
</div>
|
||||
</div>
|
||||
<logo-carousel></logo-carousel>
|
||||
</div>
|
||||
</div>
|
||||
<%- /* Expose locals as `window.SAILS_LOCALS` :: */ exposeLocalsToBrowser() %>
|
||||
|
|
|
|||
Loading…
Reference in a new issue