Website: Update login/register flow, add Fleet UI background to /try and /login (#39290)

Closes: https://github.com/fleetdm/fleet/issues/36465
Closes: https://github.com/fleetdm/fleet/issues/36467
Related to: https://github.com/fleetdm/confidential/issues/14254

Changes:
- Updated "Try it yourself" links to go to the `/try` page (Which
redirects users who aren't logged in to the /login page)
- Removed the `<signup-modal>` and `<signup-button>` components
- Removed the route for the /register page, and added a redirect to go
to /login
- Updated the /login page to have the signup form, and to match the
latest wireframes
- Updated the /try page to have a fake Fleet UI as a background
(previously an image)
This commit is contained in:
Eric
2026-02-10 12:32:49 -06:00
committed by GitHub
parent dc4e50ef7b
commit 75ffd8b12f
52 changed files with 2337 additions and 644 deletions
+1 -1
View File
@@ -25,7 +25,7 @@ module.exports = {
// if the user isn't logged in, we'll redirect them to the register page.
if (!this.req.me) {
throw {redirect: '/register#purchaseLicense'};
throw {redirect: '/login#purchaseLicense'};
}
// If the user is a super admin, we'll redirect them to the generate-license page.
if(this.req.me.isSuperAdmin) {
+1 -1
View File
@@ -64,7 +64,7 @@ parasails.registerComponent('callToAction', {
</div>
<div purpose="default-cta" v-else>
<a purpose="cta-button" href="/contact">Get a demo</a>
<animated-arrow-button href="/register">Try it yourself</animated-arrow-button>
<!-- <animated-arrow-button href="/register">Try it yourself</animated-arrow-button> -->
</div>
</div>
`,
-57
View File
@@ -1,57 +0,0 @@
/**
* <signup-button>
* -----------------------------------------------------------------------------
* An animated arrow button that either opens the signup model or sends logged-in users to the Fleet Premium trial page.
*
* @type {Component}
*
* Example usage:
* <signup-button :is-logged-in="!! this.me"></signup-button>
*
* -----------------------------------------------------------------------------
*/
parasails.registerComponent('signupButton', {
// ╔═╗╦═╗╔═╗╔═╗╔═╗
// ╠═╝╠╦╝║ ║╠═╝╚═╗
// ╩ ╩╚═╚═╝╩ ╚═╝
props: [
'isLoggedIn',
],
// ╦╔╗╔╦╔╦╗╦╔═╗╦ ╔═╗╔╦╗╔═╗╔╦╗╔═╗
// ║║║║║ ║ ║╠═╣║ ╚═╗ ║ ╠═╣ ║ ║╣
// ╩╝╚╝╩ ╩ ╩╩ ╩╩═╝ ╚═╝ ╩ ╩ ╩ ╩ ╚═╝
data: function (){
return {};
},
// ╦ ╦╔╦╗╔╦╗╦
// ╠═╣ ║ ║║║║
// ╩ ╩ ╩ ╩ ╩╩═╝
template: `
<div>
<animated-arrow-button href="/try" v-if="isLoggedIn">Try it yourself</animated-arrow-button>
<animated-arrow-button data-toggle="modal" data-target="#signupmodal" v-else>Try it yourself</animated-arrow-button>
</div>
`,
// ╦ ╦╔═╗╔═╗╔═╗╦ ╦╔═╗╦ ╔═╗
// ║ ║╠╣ ║╣ ║ ╚╦╝║ ║ ║╣
// ╩═╝╩╚ ╚═╝╚═╝ ╩ ╚═╝╩═╝╚═╝
beforeMount: function() {
//…
},
mounted: async function(){
//…
},
beforeDestroy: function() {
//…
},
// ╦╔╗╔╔╦╗╔═╗╦═╗╔═╗╔═╗╔╦╗╦╔═╗╔╗╔╔═╗
// ║║║║ ║ ║╣ ╠╦╝╠═╣║ ║ ║║ ║║║║╚═╗
// ╩╝╚╝ ╩ ╚═╝╩╚═╩ ╩╚═╝ ╩ ╩╚═╝╝╚╝╚═╝
methods: {
//…
}
});
-301
View File
@@ -1,301 +0,0 @@
/**
* <signup-modal>
* -----------------------------------------------------------------------------
* A modal with a combined signup/login form
*
* @type {Component}
*
*
* @event close [emitted when the closing process begins]
* @event opened [emitted when the opening process is completely done]
* -----------------------------------------------------------------------------
*/
parasails.registerComponent('signupModal', {
// ╔═╗╦═╗╔═╗╔═╗╔═╗
// ╠═╝╠╦╝║ ║╠═╝╚═╗
// ╩ ╩╚═╚═╝╩ ╚═╝
props: [
// No props.
],
// ╦╔╗╔╦╔╦╗╦╔═╗╦ ╔═╗╔╦╗╔═╗╔╦╗╔═╗
// ║║║║║ ║ ║╠═╣║ ╚═╗ ║ ╠═╣ ║ ║╣
// ╩╝╚╝╩ ╩ ╩╩ ╩╩═╝ ╚═╝ ╩ ╩ ╩ ╩ ╚═╝
data: function (){
return {
formToDisplay: 'signup',
// Shared by forms
syncing: false,
cloudError: undefined,
// Signup form
signupFormData: {},
signupFormErrors: {},
signupFormRules: {
firstName: {required: true},
lastName: {required: true},
emailAddress: {required: true, isEmail: true},
password: {
required: true,
minLength: 12,
maxLength: 48,
custom: (value)=>{
return value.match(/^(?=.*\d)(?=.*[^A-Za-z0-9]).{12,48}$/);
}
},
},
// Login form
loginFormData: {},
loginFormErrors: {},
loginFormRules: {
emailAddress: {required: true, isEmail: true},
password: {required: true},
},
// For <modal>
_bsModalIsAnimatingOut: false,
originalScrollPosition: undefined,//« more on this below
};
},
// ╦ ╦╔╦╗╔╦╗╦
// ╠═╣ ║ ║║║║
// ╩ ╩ ╩ ╩ ╩╩═╝
template: `
<transition name="modal" v-on:leave="leave" v-bind:css="false">
<div class="modal" id="signupmodal" tabindex="-1" role="dialog" data-dismiss="modal" data-target="#signupmodal" @click="$emit('close')">
<div class="petticoat"></div>
<div class="modal-dialog custom-width position-relative" role="document" purpose="modal-dialog" >
<div class="modal-content" purpose="modal-content" >
<button type="button" class="position-absolute" data-dismiss="modal" data-target="#signupmodal" aria-label="Close" purpose="modal-close-button" @click="$emit('close')">&times;</button>
<div purpose="signup-modal">
<div purpose="modal-logo">
<img alt="Fleet logo" src="/images/logo-brandmark-32x32@2x.png">
</div>
<h3 class="mb-0">Welcome to Fleet</h3>
<p class="mb-0">We just need a few details in order to get started.</p>
<div purpose="form-switch" class="d-flex flex-column">
<label purpose="form-option" class="form-control" :class="[formToDisplay === 'login' ? 'selected' : '']">
<input type="radio" v-model.trim="formToDisplay" value="login" @selected="switchForm('login')">
<span purpose="custom-radio"><span purpose="custom-radio-selected"></span></span>
I have an account
</label>
<label purpose="form-option" class="form-control" :class="[formToDisplay === 'signup' ? 'selected' : '']">
<input type="radio" v-model.trim="formToDisplay" value="signup" @selected="switchForm('signup')">
<span purpose="custom-radio"><span purpose="custom-radio-selected"></span></span>
I don't have an account
</label>
</div>
<ajax-form action="signup" purpose="modal-form" class="self-service-register" :syncing.sync="syncing" :cloud-error.sync="cloudError" :form-errors.sync="signupFormErrors" :form-data="signupFormData" :form-rules="signupFormRules" @submitted="submittedSignupForm()" v-if="formToDisplay === 'signup'">
<div class="form-group">
<label purpose="modal-form-label" for="email-address">Work email *</label>
<input tabindex="1" purpose="modal-form-input" class="form-control" id="email-address" :class="[signupFormErrors.emailAddress ? 'is-invalid' : '']" v-model.trim="signupFormData.emailAddress" @input="typeClearOneFormError('emailAddress')">
<div class="invalid-feedback" v-if="signupFormErrors.emailAddress" focus-first>This doesnt appear to be a valid email address</div>
</div>
<div class="form-group">
<label purpose="modal-form-label" for="password">Choose a password *</label>
<input tabindex="2" purpose="modal-form-input" class="form-control" id="password" type="password" :class="[signupFormErrors.password ? 'is-invalid' : '']" v-model.trim="signupFormData.password" autocomplete="new-password" @input="typeClearOneFormError('password')">
<div class="invalid-feedback" v-if="signupFormErrors.password === 'minLength'">Password too short.</div>
<div class="invalid-feedback" v-if="signupFormErrors.password === 'maxLength'">Password too long.</div>
<div class="invalid-feedback" v-if="signupFormErrors.password === 'custom'">Password does not meet requirements.</div>
<div class="invalid-feedback" v-if="signupFormErrors.password === 'required'">Please enter a password.</div>
<p purpose="modal-form-note" class="mt-2">Passwords must be 12-48 characters, with at least 1 number (e.g. 0 - 9) and 1 symbol (e.g. &*#).</p>
</div>
<div class="row">
<div class="col-12 col-sm-6 pr-sm-2">
<div class="form-group">
<label purpose="modal-form-label" for="first-name">First name *</label>
<input tabindex="4" purpose="modal-form-input" class="form-control" id="first-name" type="text" :class="[signupFormErrors.firstName ? 'is-invalid' : '']" v-model.trim="signupFormData.firstName" autocomplete="first-name" @input="typeClearOneFormError('firstName')">
<div class="invalid-feedback" v-if="signupFormErrors.firstName">Please enter your first name.</div>
</div>
</div>
<div class="col-12 col-sm-6 pl-sm-2">
<div class="form-group">
<label purpose="modal-form-label" for="last-name">Last name *</label>
<input tabindex="5" purpose="modal-form-input" class="form-control" id="last-name" type="text" :class="[signupFormErrors.lastName ? 'is-invalid' : '']" v-model.trim="signupFormData.lastName" autocomplete="last-name" @input="typeClearOneFormError('lastName')">
<div class="invalid-feedback" v-if="signupFormErrors.lastName">Please enter your last name.</div>
</div>
</div>
</div>
<cloud-error v-if="cloudError==='emailAlreadyInUse'">
This email is already linked to a Fleet account.<br> Please <a purpose="modal-form-link" @click="formToDisplay = 'login'">sign in</a> with your email and password.
</cloud-error>
<cloud-error v-if="cloudError === 'invalidEmailDomain'">
Please enter your work or school email address.
</cloud-error>
<blockquote purpose="tip" v-if="cloudError === 'invalidEmailDomain'">
<img src="/images/icon-info-16x16@2x.png" alt="An icon indicating that this section has important information">
<div class="d-block">
<p>Dont have a work email? Try a local demo of <a purpose="modal-form-link" href="/try-fleet">Fleet Free</a> instead.</p>
</div>
</blockquote>
<cloud-error purpose="cloud-error" v-if="cloudError && !['emailAlreadyInUse', 'invalidEmailDomain'].includes(cloudError)"></cloud-error>
<p purpose="modal-form-note">By signing up you agree to our <a purpose="modal-form-link" href="/legal/privacy">privacy policy</a> and <a purpose="modal-form-link" href="/terms">terms of service</a>.</p>
<ajax-button tabindex="6" purpose="modal-form-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 tabindex="7" purpose="modal-form-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>
<ajax-form class="w-100" action="login" purpose="modal-form" :syncing.sync="syncing" :cloud-error.sync="cloudError" :form-data="loginFormData" :form-rules="loginFormRules" :form-errors.sync="loginFormErrors" @submitted="submittedLoginForm()" v-else>
<div class="form-group">
<label purpose="modal-form-label" for="email">Email</label>
<input tabindex="1" type="email" purpose="modal-form-input" class="form-control" :class="[loginFormErrors.emailAddress ? 'is-invalid' : '']" v-model.trim="loginFormData.emailAddress" autocomplete="email" focus-first>
<div class="invalid-feedback" v-if="loginFormErrors.emailAddress">Please provide a valid email address.</div>
</div>
<div class="form-group">
<label purpose="modal-form-label" for="password">Password</label>
<input tabindex="2" type="password" purpose="modal-form-input" class="form-control" :class="[loginFormErrors.password ? 'is-invalid' : '']" v-model.trim="loginFormData.password" autocomplete="current-password">
<div class="invalid-feedback" v-if="loginFormErrors.password">Please enter your password.</div>
</div>
<cloud-error v-if="cloudError === 'noUser'">The email address provided doesn't match an existing account. Create an account <a purpose="modal-form-link" @click="formToDisplay = 'signup'">here</a>.</cloud-error>
<cloud-error v-else-if="cloudError === 'badCombo'">Somethings not quite right with your email or password.</cloud-error>
<cloud-error v-else-if="cloudError"></cloud-error>
<div class="pb-3">
<ajax-button tabindex="3" :syncing="syncing" spinner="true" purpose="modal-form-submit-button" class="btn-primary mt-4 btn-lg btn-block">Sign in</ajax-button>
</div>
<span purpose="modal-form-note" class="text-center"><a purpose="modal-form-link" href="/customers/forgot-password">Forgot your password?</a></span>
</ajax-form>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
</transition>
`,
// ╦ ╦╔═╗╔═╗╔═╗╦ ╦╔═╗╦ ╔═╗
// ║ ║╠╣ ║╣ ║ ╚╦╝║ ║ ║╣
// ╩═╝╩╚ ╚═╝╚═╝ ╩ ╚═╝╩═╝╚═╝
beforeMount: function() {
//…
},
mounted: async function(){
// ^^ Note that this is not an `async function`.
// This is just to be safe, since the timing here is a little tricky w/ the
// animations and the fact that we're integrating with Bootstrap's modal.
// (That said, it might work fine-- just hasn't been extensively tested.)
// Immediately call out to the Bootstrap modal and tell it to show itself.
$(this.$el).modal({
// Set the modal backdrop to the 'static' option, which means it doesn't close the modal
// when clicked.
backdrop: 'static',
show: false
});
// Attach listener for underlying custom modal closing event,
// and when that happens, have Vue emit a custom "close" event.
// (Note: This isn't just for convenience-- it's crucial that
// the parent logic can use this event to update its scope.)
$(this.$el).on('hide.bs.modal', ()=>{
// Close the mobile navigation menu if it is open.
$('#navbarToggleExternalContent').collapse('hide');
this._bsModalIsAnimatingOut = true;
this.$emit('close');
});//œ
// Attach listener for underlying custom modal "opened" event,
// and when that happens, have Vue emit our own custom "opened" event.
// This is so we know when the entry animation has completed, allows
// us to do cool things like auto-focus the first input in a form modal.
$(this.$el).on('shown.bs.modal', ()=>{
$('.modal-backdrop.show').addClass('signup');
// Focus our "focus-first" field, if relevant.
// (but not on mobile, because it can get weird)
if(typeof bowser !== 'undefined' && !bowser.mobile && this.$find('[focus-first]').length > 0) {
this.$focus('[focus-first]');
}
this.$emit('opened');
// $(this.$el).off('shown.bs.modal');
});//ƒ
},
watch: {
formToDisplay: function() {
// Reset forms and form errors when the form is switched.
this.signupFormData = {};
this.signupFormErrors = {};
this.loginFormData = {};
this.loginFormErrors = {};
this.cloudError = undefined;
}
},
// ╦╔╗╔╔╦╗╔═╗╦═╗╔═╗╔═╗╔╦╗╦╔═╗╔╗╔╔═╗
// ║║║║ ║ ║╣ ╠╦╝╠═╣║ ║ ║║ ║║║║╚═╗
// ╩╝╚╝ ╩ ╚═╝╩╚═╩ ╩╚═╝ ╩ ╩╚═╝╝╚╝╚═╝
methods: {
switchForm(form) {
this.formToDisplay = form;
},
clickResetForm: async function() {
this.cloudError = '';
this.signupFormErrors = {};
await this.forceRender();
},
typeClearOneFormError: async function(field) {
if(this.signupFormErrors[field]){
this.signupFormErrors = _.omit(this.signupFormErrors, field);
}
},
submittedSignupForm: async function(){
this.syncing = true;
// Track a "key event" in Google Analytics.
// > Naming convention: (like sails config)
// > "Website - Sign up" becomes "fleet_website__sign_up" (double-underscore representing hierarchy)
if(window.gtag !== undefined){
window.gtag('event','fleet_website__sign_up');
}
// Track a "conversion" in LinkedIn Campaign Manager.
if(window.lintrk !== undefined) {
window.lintrk('track', { conversion_id: 18587097 });// eslint-disable-line camelcase
}
this.goto('/try');
},
submittedLoginForm: async function() {
this.syncing = true;
this.goto('/try');
},
leave: function (el, done) {
// > Note: This function signature comes from Vue.js's transition system.
// > It will likely be replaced with `async function (el){…}` in a future
// > release of Vue/Sails.js (i.e. no callback argument).
// If this shutting down was spawned by the bootstrap modal's built-in logic,
// then we'll have already begun animating the modal shut. So we check our
// spinlock to make sure. If it turns out that we HAVEN'T started that process
// yet, then we go ahead and start it now.
if (!this._bsModalIsAnimatingOut) {
$(this.$el).modal('hide');
}//fi
// When the bootstrap modal finishes animating into nothingness, unbind all
// the DOM events used by bootstrap, and then call `done()`, which passes
// control back to Vue and lets it finish the job (i.e. afterLeave).
//
// > Note that the other lifecycle events like `destroyed` were actually
// > already fired at this point.
// >
// > Also note that, since we're potentially long past the `destroyed` point
// > of the lifecycle here, we can't call `.$emit()` anymore either. So,
// > for example, we wouldn't be able to emit a "fullyClosed" event --
// > because by the time it'd be appropriate to emit the Vue event, our
// > context for triggering it (i.e. the relevant instance of this component)
// > will no longer be capable of emitting custom Vue events (because by then,
// > it is no longer "reactive").
// >
// > For more info, see:
// > https://github.com/vuejs/vue-router/issues/1302#issuecomment-291207073
$(this.$el).on('hidden.bs.modal', ()=>{
$(this.$el).off('hide.bs.modal');
$(this.$el).off('hidden.bs.modal');
$(this.$el).off('shown.bs.modal');
done();
});//_∏_
},
}
});
+84 -35
View File
@@ -3,55 +3,69 @@ parasails.registerPage('login', {
// ║║║║║ ║ ║╠═╣║ ╚═╗ ║ ╠═╣ ║ ║╣
// ╩╝╚╝╩ ╩ ╩╩ ╩╩═╝ ╚═╝ ╩ ╩ ╩ ╩ ╚═╝
data: {
// Default to the login form
formToDisplay: 'login',
// Shared by forms
// Main syncing/loading state for this page.
syncing: false,
// Server error state for the form
cloudError: undefined,
// Form data
formData: {
rememberMe: true,
},
// Signup form data
signupFormData: {},
// For tracking client-side validation errors in our form.
// > Has property set to `true` for each invalid property in `formData`.
formErrors: { /* … */ },
signupFormErrors: {},
// A set of validation rules for our form.
// > The form will not be submitted if these are invalid.
formRules: {
emailAddress: { required: true, isEmail: true },
password: { required: true },
signupFormRules: {
firstName: {required: true},
lastName: {required: true},
emailAddress: {required: true, isEmail: true},
password: {
required: true,
minLength: 12,
maxLength: 48,
custom: (value)=>{
return value.match(/^(?=.*\d)(?=.*[^A-Za-z0-9]).{12,48}$/);
}
},
},
// Server error state for the form
cloudError: '',
showCustomerLogin: true,
// Login form data
loginFormData: {},
// For tracking client-side validation errors in our form.
// > Has property set to `true` for each invalid property in `formData`.
loginFormErrors: {},
// A set of validation rules for our form.
// > The form will not be submitted if these are invalid.
loginFormRules: {
emailAddress: {required: true, isEmail: true},
password: {required: true},
},
// For redirecting users coming from the "Get your license" link to the license dispenser.
registerSlug: '/register',
pageToRedirectToAfterLogin: '/try',
pageToRedirectToAfterFormSubmission: '/try',
},
// ╦ ╦╔═╗╔═╗╔═╗╦ ╦╔═╗╦ ╔═╗
// ║ ║╠╣ ║╣ ║ ╚╦╝║ ║ ║╣
// ╩═╝╩╚ ╚═╝╚═╝ ╩ ╚═╝╩═╝╚═╝
beforeMount: function() {
if(window.location.search === '?admin') {
this.showCustomerLogin = false;
}
if(window.location.hash){
// If we're redirecting this user to the license dispenser after they log in, modify the link to the /register page and the pageToRedirectToAfterLogin.
if(window.location.hash === '#purchaseLicense'){
this.registerSlug = '/register#purchaseLicense';
this.pageToRedirectToAfterLogin = '/new-license';
if(window.location.hash === '#register') {
// IF a user was sent here by a /register redirect, show the signup form.
this.formToDisplay = 'signup';
window.location.hash = '';
// If we're redirecting this user to the contact form after they log in, modify the link to the /register page and the pageToRedirectToAfterLogin.
// If we're redirecting this user to the license dispenser after they log in, modify the link to the /register page and the pageToRedirectToAfterLogin.
} else if(window.location.hash === '#purchaseLicense'){
this.pageToRedirectToAfterFormSubmission = '/new-license';
window.location.hash = '';
// If we're redirecting this user to the contact form after they log in, modify the link to the /register page and the pageToRedirectToAfterFormSubmission.
} else if(window.location.hash === '#contact'){
this.registerSlug = '/register';
this.pageToRedirectToAfterLogin = '/contact?sendMessage';
this.pageToRedirectToAfterFormSubmission = '/contact?sendMessage';
window.location.hash = '';
} else if(window.location.hash === '#tryfleet'){
this.registerSlug = '/register#tryfleet';
this.pageToRedirectToAfterLogin = '/try-fleet';
this.pageToRedirectToAfterFormSubmission = '/try-fleet';
window.location.hash = '';
}
}
@@ -65,14 +79,49 @@ parasails.registerPage('login', {
// ║║║║ ║ ║╣ ╠╦╝╠═╣║ ║ ║║ ║║║║╚═╗
// ╩╝╚╝ ╩ ╚═╝╩╚═╩ ╩╚═╝ ╩ ╩╚═╝╝╚╝╚═╝
methods: {
submittedForm: async function() {
// Redirect to the /start page on success.
// > (Note that we re-enable the syncing state here. This is on purpose--
// > to make sure the spinner stays there until the page navigation finishes.)
this.syncing = true;
this.goto(this.pageToRedirectToAfterLogin);
switchForm(form) {
this.formToDisplay = form;
},
clickResetForm: async function() {
this.cloudError = '';
this.signupFormErrors = {};
await this.forceRender();
},
typeClearOneFormError: async function(field) {
if(this.signupFormErrors[field]){
this.signupFormErrors = _.omit(this.signupFormErrors, field);
}
},
submittedSignupForm: async function(){
this.syncing = true;
// Track a "key event" in Google Analytics.
// > Naming convention: (like sails config)
// > "Website - Sign up" becomes "fleet_website__sign_up" (double-underscore representing hierarchy)
if(window.gtag !== undefined){
window.gtag('event','fleet_website__sign_up');
}
// Track a "conversion" in LinkedIn Campaign Manager.
if(window.lintrk !== undefined) {
window.lintrk('track', { conversion_id: 18587097 });// eslint-disable-line camelcase
}
this.goto(this.pageToRedirectToAfterFormSubmission);
},
submittedLoginForm: async function() {
this.syncing = true;
this.goto(this.pageToRedirectToAfterFormSubmission);
},
clickGoBack: function () {
if(window.navigation && window.navigation.canGoBack){
window.navigation.back();
} else {
this.goto('/');
}
}
}
});
+6
View File
@@ -22,6 +22,12 @@ parasails.registerPage('fleet-premium-trial', {
methods: {
closeModalAndRedirect: function() {
if(window.navigation && window.navigation.canGoBack){
if(window.navigation.entries()){
let recentNavigationEntries = window.navigation.entries();
if(recentNavigationEntries && ['http://localhost:2024/login', 'https://fleetdm.com/login'].includes(recentNavigationEntries[0].url)) {
this.goto('/');
}
}
window.navigation.back();
} else {
this.goto('/');
-1
View File
@@ -21,7 +21,6 @@
@import 'components/stripe-card-element.component.less';
@import 'components/ajax-button.component.less';
@import 'components/modal.component.less';
@import 'components/signup-modal.component.less';
@import 'components/cloud-error.component.less';
@import 'components/bar-chart.component.less';
@import 'components/call-to-action.component.less';
+844 -3
View File
@@ -1,4 +1,584 @@
#login {
[purpose='fleet-ui-background'] {
opacity: 1;
background: linear-gradient(0deg, #FFF 87.44%, #EFF6FA 100%);
height: 100vh;
width: 100vw;
position: fixed;
z-index: 1;
overflow: hidden;
pointer-events: none;
&::after {// veil over fake elements.
content: ' ';
position: absolute;
top: 0px;
background: rgba(25, 33, 71, 0.25);
height: 100vh;
width: 100vw;
}
[purpose='g-header'] {
background: #FFF;
height: 50px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
[purpose='g-header-left'] {
display: flex;
flex-direction: row;
align-items: center;
}
[purpose='g-header-logo'] {
width: 64px;
height: 50px;
display: flex;
align-items: center;
justify-content: center;
border-bottom: 1px solid @core-fleet-black;
img {
height: 32px;
}
}
[purpose='g-header-links'] {
display: flex;
flex-direction: row;
padding-left: 16px;
gap: 16px;
[purpose='g-link'] {
border-radius: 4px;
background: #E2E4EA;
width: 56px;
height: 12px;
}
}
[purpose='g-header-right'] {
padding-right: 24px;
gap: 8px;
display: flex;
align-items: center;
[purpose='g-header-avatar'] {
img {
height: 24px;
}
}
}
}
[purpose='g-content'] {
min-height: 900px;
display: flex;
padding: 32px 64px;
max-width: 1400px;
margin-left: auto;
margin-right: auto;
flex-direction: column;
align-items: flex-start;
gap: 24px;
flex: 1 0 0;
[purpose='g-page-header'] {
display: flex;
width: 100%;
height: 36px;
flex-direction: column;
justify-content: center;
align-items: flex-start;
gap: 24px;
div {
border-radius: 4px;
background: #C5C7D1;
width: 341px;
height: 12px;
}
}
}
[purpose='g-team-select'] {
display: flex;
flex-direction: row;
align-items: center;
gap: 8px;
[purpose='g-label'] {
border-radius: 4px;
background: #C5C7D1;
width: 56px;
height: 12px;
}
[purpose='g-select'] {
[purpose='g-label'] {
border-radius: 4px;
background: #C5C7D1;
width: 80px;
height: 12px;
flex-shrink: 0;
}
display: flex;
width: 180px;
height: 36px;
padding: 4px 8px 4px 16px;
justify-content: space-between;
align-items: center;
border-radius: 4px;
border: 1px solid #E2E4EA;
background: #FFF;
}
}
[purpose='g-platforms'] {
display: grid;
grid-template-columns: repeat(6, 1fr);
grid-template-rows: auto;
align-items: stretch;
gap: 16px;
align-self: stretch;
flex-wrap: wrap;
[purpose='g-platform'] {
display: flex;
grid-column: span 1;
padding: 32px;
flex-direction: column;
justify-content: center;
align-items: center;
min-width: 0px;
gap: 16px;
border-radius: 16px;
border: 1px solid #E2E4EA;
background: #FFF;
[purpose='g-icon'] {
border-radius: 4px;
background: #F2F2F5;
display: flex;
width: 44px;
height: 44px;
padding: 4px;
justify-content: center;
align-items: center;
gap: 4px;
}
[purpose='g-label'] {
width: 55px;
height: 12px;
border-radius: 4px;
background: #C5C7D1;
margin-bottom: 4px;
}
[purpose='g-bottom-label'] {
width: 55px;
height: 12px;
border-radius: 4px;
background: #E2E4EA;
}
}
}
[purpose='g-label-25'] {
border-radius: 4px;
background: #C5C7D1;
}
[purpose='g-label-10'] {
border-radius: 4px;
background: #E2E4EA;
}
[purpose='g-details'] {
display: flex;
flex-direction: row;
width: 100%;
gap: 24px;
flex-wrap: wrap;
[purpose='g-table'] {
display: flex;
padding: 32px;
flex-direction: column;
align-items: flex-start;
gap: 24px;
flex: 1 0 0;
align-self: stretch;
border-radius: 16px;
border: 1px solid #E2E4EA;
background: #FFF;
width: 50%;
[purpose='g-table-headings'] {
display: flex;
flex-direction: row;
justify-content: space-between;
width: 100%;
[purpose='g-labels'] {
display: flex;
gap: 8px;
div {
width: 80px;
height: 12px;
}
}
[purpose='g-link'] {
width: 100px;
height: 12px;
border-radius: 8px;
background: #C5C7D1;
}
}
[purpose='g-table-links'] {
display: flex;
align-items: flex-start;
gap: 40px;
align-self: stretch;
border-bottom: 1px solid #E2E4EA;
height: 44px;
[purpose='g-label-25'] {
margin: 8px 0 16px 0;
width: 40px;
height: 12px;
// border-bottom: 1px solid #8B8FA2;
}
[purpose='g-label-10'] {
margin: 8px 0 16px 0;
width: 80px;
height: 12px;
}
}
[purpose='g-table-body'] {
border-radius: 4px;
outline: 1px solid #E2E4EA;
display: flex;
flex-direction: column;
align-items: flex-start;
align-self: stretch;
[purpose='g-th'] {
border-bottom: 1px solid #E2E4EA;
background: #F9FAFC;
display: flex;
width: 100%;
justify-content: stretch;
[purpose='g-td'] {
border-right: 1px solid #E2E4EA;
&:last-child {
border-right: none;
}
align-items: center;
height: 40px;
padding: 0 24px;
gap: 8px;
display: flex;
width: 25%;
&:first-of-type {
width: 50%;
}
[purpose='g-label-25'] {
width: 60px;
height: 12px;
}
}
}
[purpose='g-tr'] {
border-bottom: 1px solid #E2E4EA;
display: flex;
width: 100%;
justify-content: stretch;
&:last-child {
border: none;
}
[purpose='g-td'] {
align-items: center;
height: 40px;
padding: 0 24px;
gap: 8px;
display: flex;
// min-width: 137px;
width: 25%;
&:first-of-type {
// min-width: 290px;
width: 50%;
[purpose='g-label-10'] {
width: 130px;
height: 12px;
}
}
[purpose='g-label-10'] {
width: 40px;
height: 12px;
}
}
}
}
[purpose='g-table-pagination'] {
display: flex;
justify-content: flex-end;
width: 100%;
align-items: center;
gap: 24px;
[purpose='g-label-10'] {
width: 60px;
height: 12px;
}
[purpose='g-label-25'] {
width: 60px;
height: 12px;
}
[purpose='pagination-button'] {
display: flex;
padding: 4px 8px 4px 4px;
justify-content: center;
align-items: center;
gap: 4px;
&:last-of-type {
img {
transform: rotate(180deg);
}
}
}
}
}
[purpose='g-log'] {
display: flex;
padding: 32px;
flex-direction: column;
align-items: flex-start;
gap: 24px;
flex: 1 0 0;
align-self: stretch;
border-radius: 16px;
border: 1px solid #E2E4EA;
background: #FFF;
width: 50%;
[purpose='g-log-header'] {
display: flex;
justify-content: flex-start;
[purpose='g-label-25'] {
width: 80px;
height: 12px;
}
}
[purpose='g-log-body'] {
padding-left: 16px;
height: 100%;
width: 100%;
display: flex;
gap: 16px;
overflow: scroll;
[purpose='left-column'] {
height: 75%;
border-left: 1px dashed #C5C7D1;
}
[purpose='g-log-box'] {
width: 32px;
height: 32px;
border-radius: 4px;
background: #F2F2F5;
margin-bottom: 32px;
margin-left: -16px;
}
[purpose='right-column'] {
height: fit-content;
width: 100%;
[purpose='g-log-item'] {
display: flex;
flex-direction: column;
margin-bottom: 32px;
gap: 10px;
[purpose='first-line'] {
display: flex;
gap: 10px;
width: 100%;
[purpose='g-label-25'] {
width: 89px;
height: 12px;
&:first-of-type {
width: 59px;
height: 12px;
}
}
[purpose='g-label-10'] {
width: 133px;
height: 12px;
&:first-of-type {
width: 185px;
height: 12px;
}
}
}
[purpose='second-line'] {
display: flex;
width: 100%;
[purpose='g-label-10'] {
width: 80px;
height: 12px;
}
}
}
}
}
}
}
[purpose='g-hosts-table'] {
width: 100%;
[purpose='g-table'] {
display: flex;
padding: 32px;
flex-direction: column;
align-items: flex-start;
gap: 24px;
flex: 1 0 0;
align-self: stretch;
border-radius: 16px;
border: 1px solid #E2E4EA;
background: #FFF;
width: 100%;
[purpose='g-table-headings'] {
display: flex;
flex-direction: row;
justify-content: space-between;
width: 100%;
[purpose='g-labels'] {
display: flex;
gap: 8px;
div {
width: 80px;
height: 12px;
}
}
}
[purpose='g-table-subheadings'] {
display: flex;
flex-direction: row;
justify-content: space-between;
width: 100%;
[purpose='g-labels'] {
display: flex;
gap: 8px;
div {
width: 133px;
height: 12px;
&:first-of-type {
width: 185px;
}
}
}
}
[purpose='g-table-links'] {
display: flex;
align-items: flex-start;
gap: 40px;
align-self: stretch;
border-bottom: 1px solid #E2E4EA;
height: 44px;
[purpose='g-label-25'] {
margin: 8px 0 16px 0;
width: 40px;
height: 12px;
}
[purpose='g-label-10'] {
margin: 8px 0 16px 0;
width: 80px;
height: 12px;
}
}
[purpose='g-table-body'] {
border-radius: 4px;
outline: 1px solid #E2E4EA;
display: flex;
flex-direction: column;
align-items: flex-start;
align-self: stretch;
[purpose='g-th'] {
border-bottom: 1px solid #E2E4EA;
background: #F9FAFC;
display: flex;
width: 100%;
justify-content: stretch;
[purpose='g-td'] {
border-right: 1px solid #E2E4EA;
&:last-child {
border-right: none;
}
align-items: center;
height: 40px;
padding: 0 24px;
gap: 8px;
display: flex;
// min-width: 137px;
width: 75%;
&:first-of-type {
// min-width: 290px;
width: 25%;
}
[purpose='g-label-25'] {
width: 60px;
height: 12px;
}
}
}
[purpose='g-tr'] {
border-bottom: 1px solid #E2E4EA;
display: flex;
width: 100%;
justify-content: stretch;
&:last-child {
border: none;
}
[purpose='g-td'] {
align-items: center;
height: 40px;
padding: 0 24px;
gap: 8px;
display: flex;
width: 75%;
&:first-of-type {
width: 25%;
[purpose='g-label-10'] {
width: 130px;
height: 12px;
}
}
[purpose='g-label-10'] {
width: 180px;
height: 12px;
}
}
}
}
[purpose='g-table-pagination'] {
display: flex;
justify-content: flex-end;
width: 100%;
align-items: center;
gap: 24px;
[purpose='g-label-10'] {
width: 60px;
height: 12px;
}
[purpose='g-label-25'] {
width: 60px;
height: 12px;
}
[purpose='pagination-button'] {
display: flex;
padding: 4px 8px 4px 4px;
justify-content: center;
align-items: center;
gap: 4px;
&:last-of-type {
img {
transform: rotate(180deg);
}
}
}
}
}
}
}
h1 {
font-size: 32px;
line-height: 120%;
@@ -131,6 +711,200 @@
font-weight: 700;
}
}
[purpose='signup-modal'] {
display: flex;
max-width: 600px;
flex-direction: column;
gap: 24px;
[purpose='logo-row'] {
display: flex;
justify-content: space-between;
align-items: flex-start;
[purpose='close-button'] {
position: relative;
top: -10px;
right: -10px;
}
[purpose='modal-logo'] {
img {
width: 32px;
height: auto;
}
}
}
[purpose='form-switch'] {
[purpose='form-option'] {
user-select: none;
cursor: pointer;
width: fit-content;
padding: 8px 16px 8px 0px;
margin-bottom: 4px !important;//lesshint-disable-line importantRule
display: flex;
flex-direction: row;
align-items: center;
border-radius: 7px;
border: none;
color: #515774 !important;//lesshint-disable-line importantRule
font-size: 14px !important;//lesshint-disable-line importantRule
font-weight: 400 !important;//lesshint-disable-line importantRule
line-height: 150%;
white-space: nowrap;
height: fit-content;
input[type='radio'] {
cursor: pointer;
margin-right: 8px;
display: none;
}
[purpose='custom-radio'] {
margin-right: 8px;
display: flex;
min-width: 18px;
min-height: 18px;
border-radius: 50%;
border: 1px solid #E2E4EA;
justify-content: center;
align-items: center;
[purpose='custom-radio-selected'] {
min-width: 10px;
min-height: 10px;
border-radius: 50%;
background-color: @core-vibrant-green;
transform: scale(0);
transition: 180ms transform ease-in-out;
}
}
input[type='radio']:checked + [purpose='custom-radio'] {
[purpose='custom-radio-selected'] {
transform: scale(1);
}
}
}
}
[purpose='modal-form'] {
[purpose='modal-form-input'] {
height: 40px;
border-radius: 6px;
}
[purpose='modal-form-label'] {
color: #192147;
font-family: Inter;
font-size: 14px;
font-style: normal;
font-weight: 700;
line-height: 21px; /* 150% */
}
[purpose='modal-form-note'] {
font-size: 12px !important;//lesshint-disable-line importantRule
}
[purpose='modal-form-link'] {
color: @core-fleet-black-75 !important;//lesshint-disable-line importantRule
cursor: pointer;
font-size: 12px !important;//lesshint-disable-line importantRule
text-decoration: underline !important;//lesshint-disable-line importantRule
text-underline-offset: 4px !important;//lesshint-disable-line importantRule
text-decoration-color: #C5C7D1 !important;//lesshint-disable-line importantRule
&:hover {
color: @core-fleet-black !important;//lesshint-disable-line importantRule
text-decoration-color: @core-fleet-black !important;//lesshint-disable-line importantRule
}
}
[parasails-component='cloud-error'] {
p {
color: @core-vibrant-red !important;//lesshint-disable-line importantRule
font-size: 14px !important;//lesshint-disable-line importantRule
a {
text-decoration-color: @core-vibrant-red !important;//lesshint-disable-line importantRule
color: @core-vibrant-red !important;//lesshint-disable-line importantRule
font-size: unset !important;//lesshint-disable-line importantRule
&:hover {
color: darken(@core-vibrant-red, 20%) !important; //lesshint-disable-line importantRule
text-decoration-color: darken(@core-vibrant-red, 20%) !important;//lesshint-disable-line importantRule
}
}
}
}
[purpose='tip'] {
margin: 16px 0 32px;
background: #F4F4FF;
padding: 16px;
border-radius: 8px;
display: flex;
img {
display: flex;
margin: 4px 12px 0 0;
height: 16px;
width: 16px;
padding: 0px;
}
p {
display: block;
margin-bottom: 16px;
line-height: 24px;
font-size: 14px !important;//lesshint-disable-line importantRule
a {
font-size: unset !important;//lesshint-disable-line importantRule
color: unset !important;//lesshint-disable-line importantRule
}
}
p:last-child {
margin-bottom: 0px;
}
}
}
[purpose='modal-form-submit-button'] {
margin-left: auto;
margin-right: auto;
border-radius: 8px;
padding-top: 16px;
padding-bottom: 16px;
display: flex;
align-items: center;
span {
display: inline;
margin-left: auto;
margin-right: auto;
font-size: 16px;
line-height: 16px;
text-align: center;
font-weight: 700;
}
}
}
[purpose='modal-dialog'] {
z-index: 100;
position: relative;
max-width: 600px;
width: 600px;
[purpose='modal-content'] {
margin-top: 0px;
max-width: 600px;
border-radius: 16px;
padding: 48px;
border: 1px solid #E2E4EA;
background: #FFF;
[purpose='modal-close-button'] {
.btn-reset();
opacity: 0.6;
color: #515774;
top: 25px;
right: 25px;
font-size: 28px;
line-height: 1;
&:hover {
opacity: 1;
}
}
}
}
@media (max-width: 1200px) {
[purpose='page-container'] {
padding: 64px;
@@ -140,6 +914,7 @@
[purpose='signup-form'] {
max-width: 528px;
}
[purpose='quote-and-logos'] {
max-width: 528px;
margin-top: 48px;
@@ -158,12 +933,52 @@
padding: 64px 32px;
}
}
@media (max-width: 768px) {
[purpose='customer-portal-form'] {
max-width: unset;
}
[purpose='signup-modal'] {
margin: auto;
width: 100%;
}
[purpose='page-container'] {
padding: 0px;
}
[purpose='modal-dialog'] {
z-index: 100;
position: relative;
max-width: 100%;
width: 100%;
margin: 0;
[purpose='modal-content'] {
box-shadow: none;
margin-top: 48px;
width: 100%;
max-width: 100%;
padding: 48px;
border: none;
[purpose='modal-close-button'] {
top: -128px;
right: -8px;
}
}
}
[purpose='fleet-ui-background'] {
&::after {// veil over fake elements.
content: ' ';
position: absolute;
top: 0px;
background: #FFF;
height: 100vh;
width: 100vw;
backdrop-filter: unset;
}
}
[purpose='login-form'] {
width: 100%;
}
@@ -180,9 +995,7 @@
padding-left: 0px;
padding-right: 0px;
}
[purpose='page-container'] {
padding: 48px 24px;
}
[purpose='register-link'] {
margin-bottom: 12px;
}
@@ -191,6 +1004,34 @@
padding: 1.5em 1em;
}
}
.modal-backdrop.signup {
background-color: #FFF;
&.show {
opacity: 1;
transition: none;
}
}
[purpose='signup-modal'] {
margin: auto;
width: 100%;
}
[purpose='modal-dialog'] {
z-index: 100;
position: relative;
max-width: 100%;
[purpose='modal-content'] {
box-shadow: none;
width: 100%;
max-width: 100%;
margin-top: 0px;
padding: 24px;
border: none;
}
}
}
}
+619 -16
View File
@@ -1,11 +1,9 @@
#fleet-premium-trial {
@text-lineheight: 150%;
background: url('/images/background-fleet-ui-1400x1264@2x.png');
background-size: cover;
height: 100vh;
min-height: 800px;
h3 {
color: var(--text-text-brand, #192147);
color: #192147;
/* Title M (FKA h3) */
font-family: Inter;
@@ -16,7 +14,7 @@
margin-bottom: 16px;
}
h4 {
color: var(--Core-Fleet-Black, #192147);
color: #192147;
margin-bottom: 4px;
/* Title XS */
@@ -65,7 +63,18 @@
padding: 48px;
background: #FFF;
border-radius: 16px;
border: 1px solid var(--border-border-primary, #E2E4EA);
border: 1px solid #E2E4EA;
}
[purpose='logo-row'] {
display: flex;
justify-content: space-between;
align-items: flex-start;
[purpose='close-button'] {
position: relative;
top: -10px;
right: -10px;
}
}
[purpose='modal-logo'] {
img {
@@ -137,7 +146,7 @@
background-repeat: no-repeat;
cursor: pointer;
z-index: 4;
background-color: var(--Off-white, #F9FAFC);
background-color: #F9FAFC;
&.copied {
display: inline-block;
background: url('/images/icon-copy-clicked-checkmark-32x32@2x.png');
@@ -170,8 +179,8 @@
flex: 1 0 0;
align-self: stretch;
border-radius: 12px;
border: 1px solid var(--UI-Fleet-Black-10, #E2E4EA);
background: var(--Core-White, #FFF);
border: 1px solid #E2E4EA;
background: #FFF;
&:hover {
box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.10);
}
@@ -180,12 +189,12 @@
margin-bottom: 16px;
}
h4 {
color: var(--Core-Fleet-Black, #192147);
color: #192147;
text-align: center;
}
p {
margin-bottom: 0px;
color: var(--UI-Fleet-Black-75, #515774);
color: #515774;
text-align: center;
/* Body XS (FKA p small) */
@@ -212,7 +221,7 @@
}
}
[purpose='contact-button'] {
color: var(--Core-White, #FFF);
color: #FFF;
text-align: center;
/* Body SM (bold) */
@@ -233,7 +242,590 @@
}
}
[purpose='fleet-ui-background'] {
opacity: 1;
min-height: 1200px;
background: linear-gradient(0deg, #FFF 87.44%, #EFF6FA 100%);
height: 100vh;
width: 100vw;
position: fixed;
z-index: 1;
overflow: hidden;
pointer-events: none;
&::after {// veil over fake elements.
content: ' ';
position: absolute;
top: 0px;
background: rgba(25, 33, 71, 0.25);
height: 100vh;
width: 100vw;
}
[purpose='g-header'] {
background: #FFF;
height: 50px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
[purpose='g-header-left'] {
display: flex;
flex-direction: row;
align-items: center;
}
[purpose='g-header-logo'] {
width: 64px;
height: 50px;
display: flex;
align-items: center;
justify-content: center;
border-bottom: 1px solid @core-fleet-black;
img {
height: 32px;
}
}
[purpose='g-header-links'] {
display: flex;
flex-direction: row;
padding-left: 16px;
gap: 16px;
[purpose='g-link'] {
border-radius: 4px;
background: #E2E4EA;
width: 56px;
height: 12px;
}
}
[purpose='g-header-right'] {
padding-right: 24px;
gap: 8px;
display: flex;
align-items: center;
[purpose='g-header-avatar'] {
img {
height: 24px;
}
}
}
}
[purpose='g-content'] {
min-height: 900px;
display: flex;
padding: 32px 64px;
max-width: 1400px;
margin-left: auto;
margin-right: auto;
flex-direction: column;
align-items: flex-start;
gap: 24px;
flex: 1 0 0;
[purpose='g-page-header'] {
display: flex;
width: 100%;
height: 36px;
flex-direction: column;
justify-content: center;
align-items: flex-start;
gap: 24px;
div {
border-radius: 4px;
background: #C5C7D1;
width: 341px;
height: 12px;
}
}
}
[purpose='g-team-select'] {
display: flex;
flex-direction: row;
align-items: center;
gap: 8px;
[purpose='g-label'] {
border-radius: 4px;
background: #C5C7D1;
width: 56px;
height: 12px;
}
[purpose='g-select'] {
[purpose='g-label'] {
border-radius: 4px;
background: #C5C7D1;
width: 80px;
height: 12px;
flex-shrink: 0;
}
display: flex;
width: 180px;
height: 36px;
padding: 4px 8px 4px 16px;
justify-content: space-between;
align-items: center;
border-radius: 4px;
border: 1px solid #E2E4EA;
background: #FFF;
}
}
[purpose='g-platforms'] {
display: grid;
grid-template-columns: repeat(6, 1fr);
grid-template-rows: auto;
align-items: stretch;
gap: 16px;
align-self: stretch;
flex-wrap: wrap;
[purpose='g-platform'] {
display: flex;
grid-column: span 1;
padding: 32px;
flex-direction: column;
justify-content: center;
align-items: center;
min-width: 0px;
gap: 16px;
// flex: 0 0 250px;
border-radius: 16px;
border: 1px solid #E2E4EA;
background: #FFF;
[purpose='g-icon'] {
border-radius: 4px;
background: #F2F2F5;
display: flex;
width: 44px;
height: 44px;
padding: 4px;
justify-content: center;
align-items: center;
gap: 4px;
}
[purpose='g-label'] {
width: 55px;
height: 12px;
border-radius: 4px;
background: #C5C7D1;
margin-bottom: 4px;
}
[purpose='g-bottom-label'] {
width: 55px;
height: 12px;
border-radius: 4px;
background: #E2E4EA;
}
}
}
[purpose='g-label-25'] {
border-radius: 4px;
background: #C5C7D1;
}
[purpose='g-label-10'] {
border-radius: 4px;
background: #E2E4EA;
}
[purpose='g-details'] {
display: flex;
flex-direction: row;
width: 100%;
gap: 24px;
flex-wrap: wrap;
[purpose='g-table'] {
display: flex;
padding: 32px;
flex-direction: column;
align-items: flex-start;
gap: 24px;
flex: 1 0 0;
align-self: stretch;
border-radius: 16px;
border: 1px solid #E2E4EA;
background: #FFF;
width: 50%;
[purpose='g-table-headings'] {
display: flex;
flex-direction: row;
justify-content: space-between;
width: 100%;
[purpose='g-labels'] {
display: flex;
gap: 8px;
div {
width: 80px;
height: 12px;
}
}
[purpose='g-link'] {
width: 100px;
height: 12px;
border-radius: 8px;
background: #C5C7D1;
}
}
[purpose='g-table-links'] {
display: flex;
align-items: flex-start;
gap: 40px;
align-self: stretch;
border-bottom: 1px solid #E2E4EA;
height: 44px;
[purpose='g-label-25'] {
margin: 8px 0 16px 0;
width: 40px;
height: 12px;
// border-bottom: 1px solid #8B8FA2;
}
[purpose='g-label-10'] {
margin: 8px 0 16px 0;
width: 80px;
height: 12px;
}
}
[purpose='g-table-body'] {
border-radius: 4px;
outline: 1px solid #E2E4EA;
display: flex;
flex-direction: column;
align-items: flex-start;
align-self: stretch;
[purpose='g-th'] {
border-bottom: 1px solid #E2E4EA;
background: #F9FAFC;
display: flex;
width: 100%;
justify-content: stretch;
[purpose='g-td'] {
border-right: 1px solid #E2E4EA;
&:last-child {
border-right: none;
}
align-items: center;
height: 40px;
padding: 0 24px;
gap: 8px;
display: flex;
// min-width: 137px;
width: 25%;
&:first-of-type {
// min-width: 290px;
width: 50%;
}
[purpose='g-label-25'] {
width: 60px;
height: 12px;
}
}
}
[purpose='g-tr'] {
border-bottom: 1px solid #E2E4EA;
display: flex;
width: 100%;
justify-content: stretch;
&:last-child {
border: none;
}
[purpose='g-td'] {
align-items: center;
height: 40px;
padding: 0 24px;
gap: 8px;
display: flex;
// min-width: 137px;
width: 25%;
&:first-of-type {
// min-width: 290px;
width: 50%;
[purpose='g-label-10'] {
width: 130px;
height: 12px;
}
}
[purpose='g-label-10'] {
width: 40px;
height: 12px;
}
}
}
}
[purpose='g-table-pagination'] {
display: flex;
justify-content: flex-end;
width: 100%;
align-items: center;
gap: 24px;
[purpose='g-label-10'] {
width: 60px;
height: 12px;
}
[purpose='g-label-25'] {
width: 60px;
height: 12px;
}
[purpose='pagination-button'] {
display: flex;
padding: 4px 8px 4px 4px;
justify-content: center;
align-items: center;
gap: 4px;
&:last-of-type {
img {
transform: rotate(180deg);
}
}
}
}
}
[purpose='g-log'] {
display: flex;
padding: 32px;
flex-direction: column;
align-items: flex-start;
gap: 24px;
flex: 1 0 0;
align-self: stretch;
border-radius: 16px;
border: 1px solid #E2E4EA;
background: #FFF;
width: 50%;
[purpose='g-log-header'] {
display: flex;
justify-content: flex-start;
[purpose='g-label-25'] {
width: 80px;
height: 12px;
}
}
[purpose='g-log-body'] {
padding-left: 16px;
height: 100%;
width: 100%;
display: flex;
gap: 16px;
overflow: scroll;
[purpose='left-column'] {
height: 75%;
border-left: 1px dashed #C5C7D1;
}
[purpose='g-log-box'] {
width: 32px;
height: 32px;
border-radius: 4px;
background: #F2F2F5;
margin-bottom: 32px;
margin-left: -16px;
}
[purpose='right-column'] {
height: fit-content;
width: 100%;
[purpose='g-log-item'] {
display: flex;
flex-direction: column;
margin-bottom: 32px;
gap: 10px;
[purpose='first-line'] {
display: flex;
gap: 10px;
width: 100%;
[purpose='g-label-25'] {
width: 89px;
height: 12px;
&:first-of-type {
width: 59px;
height: 12px;
}
}
[purpose='g-label-10'] {
width: 133px;
height: 12px;
&:first-of-type {
width: 185px;
height: 12px;
}
}
}
[purpose='second-line'] {
display: flex;
width: 100%;
[purpose='g-label-10'] {
width: 80px;
height: 12px;
}
}
}
}
}
}
}
[purpose='g-hosts-table'] {
width: 100%;
[purpose='g-table'] {
display: flex;
padding: 32px;
flex-direction: column;
align-items: flex-start;
gap: 24px;
flex: 1 0 0;
align-self: stretch;
border-radius: 16px;
border: 1px solid #E2E4EA;
background: #FFF;
width: 100%;
[purpose='g-table-headings'] {
display: flex;
flex-direction: row;
justify-content: space-between;
width: 100%;
[purpose='g-labels'] {
display: flex;
gap: 8px;
div {
width: 80px;
height: 12px;
}
}
}
[purpose='g-table-subheadings'] {
display: flex;
flex-direction: row;
justify-content: space-between;
width: 100%;
[purpose='g-labels'] {
display: flex;
gap: 8px;
div {
width: 133px;
height: 12px;
&:first-of-type {
width: 185px;
}
}
}
}
[purpose='g-table-links'] {
display: flex;
align-items: flex-start;
gap: 40px;
align-self: stretch;
border-bottom: 1px solid #E2E4EA;
height: 44px;
[purpose='g-label-25'] {
margin: 8px 0 16px 0;
width: 40px;
height: 12px;
}
[purpose='g-label-10'] {
margin: 8px 0 16px 0;
width: 80px;
height: 12px;
}
}
[purpose='g-table-body'] {
border-radius: 4px;
outline: 1px solid #E2E4EA;
display: flex;
flex-direction: column;
align-items: flex-start;
align-self: stretch;
[purpose='g-th'] {
border-bottom: 1px solid #E2E4EA;
background: #F9FAFC;
display: flex;
width: 100%;
justify-content: stretch;
[purpose='g-td'] {
border-right: 1px solid #E2E4EA;
&:last-child {
border-right: none;
}
height: 40px;
padding: 0 24px;
align-items: center;
gap: 8px;
display: flex;
// min-width: 137px;
width: 75%;
&:first-of-type {
// min-width: 290px;
width: 25%;
}
[purpose='g-label-25'] {
width: 60px;
height: 12px;
}
}
}
[purpose='g-tr'] {
border-bottom: 1px solid #E2E4EA;
display: flex;
width: 100%;
justify-content: stretch;
&:last-child {
border: none;
}
[purpose='g-td'] {
align-items: center;
height: 40px;
padding: 0 24px;
gap: 8px;
display: flex;
width: 75%;
&:first-of-type {
width: 25%;
[purpose='g-label-10'] {
width: 130px;
height: 12px;
}
}
[purpose='g-label-10'] {
width: 180px;
height: 12px;
}
}
}
}
[purpose='g-table-pagination'] {
display: flex;
justify-content: flex-end;
width: 100%;
align-items: center;
gap: 24px;
[purpose='g-label-10'] {
width: 60px;
height: 12px;
}
[purpose='g-label-25'] {
width: 60px;
height: 12px;
}
[purpose='pagination-button'] {
display: flex;
padding: 4px 8px 4px 4px;
justify-content: center;
align-items: center;
gap: 4px;
&:last-of-type {
img {
transform: rotate(180deg);
}
}
}
}
}
}
}
@media (max-width: 768px) {
background: none;
@@ -242,13 +834,20 @@
position: relative;
// max-width: 100%;
}
[purpose='fleet-ui-background'] {
&::after {// veil over fake elements.
content: ' ';
position: absolute;
top: 0px;
background: #FFF;
height: 100vh;
width: 100vw;
backdrop-filter: unset;
}
}
[purpose='modal'] {
max-width: unset;
}
[purpose='modal-close-button'] {
top: -128px;
right: -8px;
}
[purpose='modal-content'] {
position: relative;
box-shadow: none;
@@ -263,6 +862,10 @@
[purpose='modal-button-links'] {
flex-direction: column;
gap: 24px;
[purpose='modal-button'] {
height: unset;
min-height: 200px;
}
}
[purpose='modal-alt-button-links'] {
flex-direction: column;
+4 -1
View File
@@ -73,7 +73,10 @@ module.exports.bootstrap = async function() {
fleetSandboxURL: 'http://example.com',
fleetSandboxExpiresAt: 1,
fleetSandboxDemoKey: await sails.helpers.strings.uuid(),
password: await sails.helpers.passwords.hashPassword('abc123')
password: await sails.helpers.passwords.hashPassword('abc123'),
fleetPremiumTrialType: 'local trial',
fleetPremiumTrialLicenseKey: await sails.helpers.strings.uuid(),
fleetPremiumTrialLicenseKeyExpiresAt: Date.now() + (60 * 60 * 24 * 30 * 1000),
}).fetch();
// Note: We do not create a platform record to avoid potential consistency violations.
+2 -41
View File
@@ -17,7 +17,6 @@ module.exports.routes = {
action: 'view-homepage-or-redirect',
locals: {
isHomepage: true,
showHeaderCTA: true,
}
},
@@ -284,7 +283,6 @@ module.exports.routes = {
skipAssets: false,
action: 'docs/view-basic-documentation',// Meta title and description set in view action
locals: {
hideStartCTA: true,
currentSection: 'documentation',
}
},// handles /docs and /docs/foo/bar
@@ -302,25 +300,14 @@ module.exports.routes = {
locals: {
hideHeaderLinks: true,
hideFooterLinks: true,
hideStartCTA: true,
pageTitleForMeta: 'Get Fleet Premium',
pageDescriptionForMeta: 'Generate your quote and start using Fleet Premium today.',
}
},
'GET /register': {
action: 'entrance/view-signup',
locals: {
hideFooterLinks: true,
hideStartCTA: true,
pageTitleForMeta: 'Sign up',
pageDescriptionForMeta: 'Sign up for a Fleet account.',
}
},
'GET /login': {
action: 'entrance/view-login',
locals: {
hideFooterLinks: true,
hideStartCTA: true,
showConfigurationProfileLayout: true,
pageTitleForMeta: 'Log in',
pageDescriptionForMeta: 'Log in to Fleet.',
}
@@ -330,7 +317,6 @@ module.exports.routes = {
locals: {
hideHeaderLinks: true,
hideFooterLinks: true,
hideStartCTA: true,
pageTitleForMeta: 'Customer dashboard',
pageDescriptionForMeta: 'View and edit information about your Fleet Premium license.',
}
@@ -341,7 +327,6 @@ module.exports.routes = {
locals: {
hideHeaderLinks: true,
hideFooterLinks: true,
hideStartCTA: true,
pageTitleForMeta: 'Forgot password',
pageDescriptionForMeta: 'Recover the password for your Fleet customer account.',
}
@@ -351,7 +336,6 @@ module.exports.routes = {
locals: {
hideHeaderLinks: true,
hideFooterLinks: true,
hideStartCTA: true,
pageTitleForMeta: 'New password',
pageDescriptionForMeta: 'Change the password for your Fleet customer account.',
}
@@ -370,7 +354,6 @@ module.exports.routes = {
locals: {
hideFooterLinks: true,
showAdminLinks: true,
hideStartCTA: true,
},
},
@@ -380,7 +363,6 @@ module.exports.routes = {
locals: {
hideFooterLinks: true,
showAdminLinks: true,
hideStartCTA: true,
},
},
@@ -389,7 +371,6 @@ module.exports.routes = {
locals: {
hideFooterLinks: true,
showAdminLinks: true,
hideStartCTA: true,
},
},
@@ -405,7 +386,6 @@ module.exports.routes = {
locals: {
hideFooterLinks: true,
showAdminLinks: true,
hideStartCTA: true,
}
},
@@ -463,23 +443,11 @@ module.exports.routes = {
}
},
'GET /start': {
action: 'view-start',
locals: {
hideFooterLinks: true,
hideGetStartedButton: true,
hideStartCTA: true,
pageTitleForMeta: 'Start',
pageDescriptionForMeta: 'Get Started with Fleet. Spin up a local demo or get your Premium license key.',
}
},
'GET /better': {
action: 'view-transparency',
locals: {
pageDescriptionForMeta: 'Discover how Fleet simplifies IT and security, prioritizing privacy, transparency, and trust for end users.',
pageTitleForMeta: 'Better with Fleet',
hideStartCTA: true,
}
},
@@ -489,7 +457,6 @@ module.exports.routes = {
pageTitleForMeta: 'Deal registration',
pageDescriptionForMeta: 'Register an opportunity with a potential customer.',
hideFooterLinks: true,
hideStartCTA: true,
}
},
@@ -543,7 +510,6 @@ module.exports.routes = {
action: 'view-configuration-builder',
locals: {
showConfigurationProfileLayout: true,
hideStartCTA: true,
}
},
@@ -551,7 +517,6 @@ module.exports.routes = {
action: 'microsoft-proxy/view-remediate',
locals: {
showConfigurationProfileLayout: true,
hideStartCTA: true,
}
},
@@ -559,7 +524,6 @@ module.exports.routes = {
action: 'microsoft-proxy/view-turn-on-mdm',
locals: {
showConfigurationProfileLayout: true,
hideStartCTA: true,
}
},
@@ -567,14 +531,12 @@ module.exports.routes = {
action: 'view-fleet-premium-trial-or-redirect',
locals: {
showConfigurationProfileLayout: true,
hideStartCTA: true,
}
},
'GET /okta-conditional-access-error': {
action: 'view-okta-conditional-access-error',
locals: {
hideStartCTA: true,
showConfigurationProfileLayout: true,
}
},
@@ -590,7 +552,6 @@ module.exports.routes = {
'GET /fast-track': {
action: 'view-fast-track',
locals: {
hideStartCTA: true,
pageTitleForMeta: 'Fleet Fast-track',
pageDescriptionForMeta: 'Fast-track helps your team enroll devices, set up workflows, and validate configurations with Fleet experts, to get Fleet ready for production.'
}
@@ -1020,7 +981,7 @@ module.exports.routes = {
'GET /software-catalog/zoom': '/software-catalog/zoom-darwin',
'GET /software-catalog/vnc-viewer': '/software-catalog/vnc-viewer-darwin',
'GET /apps': '/software-catalog',// This is mostly for mikermcneil who keeps trying to type the old url.
'GET /register': '/login#register',
// ╔╦╗╦╔═╗╔═╗ ╦═╗╔═╗╔╦╗╦╦═╗╔═╗╔═╗╔╦╗╔═╗ ┬ ╔╦╗╔═╗╦ ╦╔╗╔╦ ╔═╗╔═╗╔╦╗╔═╗
// ║║║║╚═╗║ ╠╦╝║╣ ║║║╠╦╝║╣ ║ ║ ╚═╗ ┌┼─ ║║║ ║║║║║║║║ ║ ║╠═╣ ║║╚═╗
// ╩ ╩╩╚═╝╚═╝ ╩╚═╚═╝═╩╝╩╩╚═╚═╝╚═╝ ╩ ╚═╝ └┘ ═╩╝╚═╝╚╩╝╝╚╝╩═╝╚═╝╩ ╩═╩╝╚═╝
+12 -42
View File
@@ -5,12 +5,9 @@
var me;
var isHomepage;
var currentSection;
var showHeaderCTA;
var hideHeaderLinks;// Hides the header navigation links.
var hideFooterLinks;// Hides footer links, reduces the height of the footer to 60px;
var showAdminLinks;// Shows links to admin pages to admin users.
var hideGetStartedButton;// Hides the 'Get started' button in the website's navigation header.
var hideStartCTA;
var showConfigurationProfileLayout;
// Applies personalization for who people come from ads, so that the website makes more sense for them:
var primaryBuyingSituation;
@@ -372,11 +369,8 @@
</div>
<%}%>
</div>
<%if(!hideGetStartedButton){%>
<div purpose="mobile-nav-cta" class="d-flex flex-row align-items-center">
<!-- <div purpose="mobile-nav-cta" class="d-flex flex-row align-items-center">
<a purpose="glass-header-btn" class="align-items-center d-flex" href="/contact" no-underline>Get a demo</a>
<%if(_.has(me, 'id')) {%>
<a purpose="layout-animated-arrow-button" class="start-cta-continue-button" href="/try" no-underline>
Try it yourself
<svg purpose="animated-arrow" xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
@@ -384,18 +378,7 @@
<path purpose="chevron" d="M1.35712 1L5.64283 6L1.35712 11" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</a>
</div>
<% } else {%>
<a purpose="layout-animated-arrow-button" class="start-cta-continue-button" data-toggle="modal" data-target="#signupmodal" no-underline>
Try it yourself
<svg purpose="animated-arrow" xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
<path purpose="arrow-line" d="M1 6H9" stroke-width="2" stroke-linecap="round"/>
<path purpose="chevron" d="M1.35712 1L5.64283 6L1.35712 11" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</a>
</div>
<% }%>
<% }%>
</div> -->
</div>
</div>
<%/* Desktop Navigation bar */%>
@@ -596,29 +579,17 @@
</div>
</div>
<!-- <a purpose="layout-animated-arrow-button" class="start-cta-continue-button" href="/try" no-underline>
Try it yourself
<svg purpose="animated-arrow" xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
<path purpose="arrow-line" d="M1 6H9" stroke-width="2" stroke-linecap="round"/>
<path purpose="chevron" d="M1.35712 1L5.64283 6L1.35712 11" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</a> -->
<a purpose="glass-header-btn" class="align-items-center d-flex" href="/contact" no-underline>Get a demo</a>
<% if(_.has(me, 'id')) {%>
<%if(!hideGetStartedButton){%>
<a purpose="layout-animated-arrow-button" class="start-cta-continue-button" href="/try" no-underline>
Try it yourself
<svg purpose="animated-arrow" xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
<path purpose="arrow-line" d="M1 6H9" stroke-width="2" stroke-linecap="round"/>
<path purpose="chevron" d="M1.35712 1L5.64283 6L1.35712 11" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</a>
<a purpose="glass-header-btn" class="align-items-center d-flex" href="/contact" no-underline>Get a demo</a>
<% }%>
<a purpose="log-out-button" href="/logout" class="justify-content-end text-decoration-none">Log out</a>
<% } else if(!hideGetStartedButton) {%>
<a purpose="layout-animated-arrow-button" class="start-cta-continue-button" data-toggle="modal" data-target="#signupmodal" no-underline>
Try it yourself
<svg purpose="animated-arrow" xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
<path purpose="arrow-line" d="M1 6H9" stroke-width="2" stroke-linecap="round"/>
<path purpose="chevron" d="M1.35712 1L5.64283 6L1.35712 11" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</a>
<a purpose="glass-header-btn" class="align-items-center d-flex" href="/contact" no-underline>Get a demo</a>
<% }%>
<% } %>
</div>
</div>
<% } else {%>
@@ -768,6 +739,7 @@
</div>
<% } %>
<% } %>
</div>
<% /*
Client-side JavaScript
========================
@@ -816,8 +788,6 @@
<script src="/js/components/parallax-city.component.js"></script>
<script src="/js/components/rituals.component.js"></script>
<script src="/js/components/scrollable-tweets.component.js"></script>
<script src="/js/components/signup-button.component.js"></script>
<script src="/js/components/signup-modal.component.js"></script>
<script src="/js/components/stripe-card-element.component.js"></script>
<script src="/js/utilities/open-stripe-checkout.js"></script>
<script src="/js/pages/account/account-overview.page.js"></script>
-1
View File
@@ -82,6 +82,5 @@
</div>
</div>
<signup-modal></signup-modal>
</div>
<%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %>
-1
View File
@@ -73,6 +73,5 @@
</div>
</div>
</div>
<signup-modal></signup-modal>
</div>
<%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %>
-1
View File
@@ -95,6 +95,5 @@
</div>
</div>
</div>
<signup-modal></signup-modal>
</div>
<%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %>
-1
View File
@@ -109,6 +109,5 @@
</div>
</div> -->
</div>
<signup-modal></signup-modal>
</div>
<%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %>
-1
View File
@@ -125,6 +125,5 @@
</div>
</div>
</div>
<signup-modal></signup-modal>
</div>
<%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %>
+1 -2
View File
@@ -113,7 +113,7 @@
<p>Fleet is the open-source endpoint management platform that gives you total control, unlike the proprietary 'black boxes' of legacy vendors. Our open device management provides full visibility into our code and roadmap, plus a true choice of deployment—on-prem or cloud—with 100% feature parity. Our API-first approach empowers technical teams to automate with GitOps, scale confidently, and get the real-time data needed to secure their entire macOS, iOS, Windows, and Linux fleets.</p>
<div purpose="button-row">
<a purpose="cta-button" href="/contact">Get a demo</a>
<signup-button :signed-in="this.me"></signup-button>
<!-- <animated-arrow-button href="/try">Try it yourself</animated-arrow-button> -->
</div>
</div>
<div purpose="bottom-case-study-links" class="d-flex d-md-none flex-column">
@@ -168,6 +168,5 @@
</div>
</div>
</div>
<signup-modal></signup-modal>
</div>
<%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %>
-1
View File
@@ -41,6 +41,5 @@
</div>
</div>
</div>
<signup-modal></signup-modal>
</div>
<%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %>
-1
View File
@@ -374,6 +374,5 @@
</div>
</div>
<p style="opacity: 0; line-height: 0px; font-size: 0px; margin: 0;">537c652d-cb1a-440e-ae35-0f0bf5743e75</p>
<signup-modal></signup-modal>
</div>
<%- /* Expose locals as `window.SAILS_LOCALS` :: */ exposeLocalsToBrowser() %>
+2 -3
View File
@@ -824,7 +824,7 @@
<div purpose="button-row" style="margin-top: 40px;" class="d-flex flex-sm-row flex-column justify-content-center align-items-center mx-auto">
<a purpose="cta-button" href="/contact">Get a demo</a>
<signup-button :is-logged-in="!! this.me"></signup-button>
<!-- <animated-arrow-button href="/try">Try it yourself</animated-arrow-button> -->
</div>
</div>
<%/* Shorten the feedback loop section */%>
@@ -914,7 +914,7 @@
<h2>Your last MDM migration</h2>
<div purpose="button-row" style="margin-top: 32px;" class="d-flex justify-content-center align-items-center mx-auto">
<a purpose="cta-button" href="/contact">Get a demo</a>
<signup-button :is-logged-in="!! this.me"></signup-button>
<!-- <animated-arrow-button href="/try">Try it yourself</animated-arrow-button> -->
</div>
</div>
</div>
@@ -924,6 +924,5 @@
<modal purpose="video-modal" v-if="modal === 'fleet-in-three-minutes'" @close="closeModal()">
<iframe width="560" height="315" src="https://www.youtube.com/embed/q1Tm3IBcx24?rel=0&autoplay=1" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
</modal>
<signup-modal></signup-modal>
</div>
<%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %>
-1
View File
@@ -157,6 +157,5 @@
</div>
</modal>
</div>
<signup-modal></signup-modal>
</div>
<%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %>
+417 -91
View File
@@ -1,107 +1,433 @@
<div id="login" v-cloak>
<!-- <div purpose="announcement-banner">
<animated-arrow-button arrow-color="white" text-color="white" href="/articles/free-migration-from-jamf-to-fleet">Free Jamf to Fleet MDM migration service</animated-arrow-button>
</div> -->
<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 purpose="fleet-ui-background">
<div purpose="g-header">
<div purpose="g-header-left">
<div purpose="g-header-logo">
<img alt="fleet-logo" src="/images/logo-brandmark-140x140@2x.png">
</div>
<div purpose="g-header-links">
<div purpose="g-link"></div>
<div purpose="g-link"></div>
<div purpose="g-link"></div>
<div purpose="g-link"></div>
<div purpose="g-link"></div>
</div>
</div>
<div purpose="g-header-right">
<div purpose="g-header-avatar">
<img alt="An avatar icon" src="/images/permanent/icon-avatar-default-gray-transparent-64x64@2x.png">
</div>
<div purpose="g-header-chevron">
<img class="d-flex" style="width: 16px; height: 16px;" src="/images/chevron-down-16x16@2x.png" alt="a small chevron pointing downwards">
</div>
</div>
</div>
<div purpose="form-container" class="d-flex flex-lg-row flex-column justify-content-between align-items-start">
<div purpose="login-form" class="mx-auto mx-lg-0">
<div purpose="customer-portal-form" class="card card-body mb-5">
<div purpose="register-link" v-if="showCustomerLogin">
<a :href="registerSlug">Create an account</a>
<div purpose="g-content">
<div purpose="g-page-header">
<div></div>
</div>
<div purpose="g-team-select">
<div purpose="g-label">
</div>
<div purpose="g-select">
<div purpose="g-label"></div>
<img class="d-flex" style="width: 16px; height: 16px;" src="/images/chevron-down-16x16@2x.png" alt="a small chevron pointing downwards">
</div>
</div>
<div purpose="g-platforms">
<div purpose="g-platform">
<div purpose="g-icon"></div>
<div>
<div purpose="g-label"></div>
<div purpose="g-bottom-label"></div>
</div>
<ajax-form class="customers-login" action="login" :syncing.sync="syncing" :cloud-error.sync="cloudError" :form-data="formData" :form-rules="formRules" :form-errors.sync="formErrors" @submitted="submittedForm()">
</div>
<div purpose="g-platform">
<div purpose="g-icon"></div>
<div>
<div purpose="g-label"></div>
<div purpose="g-bottom-label"></div>
</div>
</div>
<div purpose="g-platform">
<div purpose="g-icon"></div>
<div>
<div purpose="g-label"></div>
<div purpose="g-bottom-label"></div>
</div>
</div>
<div purpose="g-platform">
<div purpose="g-icon"></div>
<div>
<div purpose="g-label"></div>
<div purpose="g-bottom-label"></div>
</div>
</div>
<div purpose="g-platform">
<div purpose="g-icon"></div>
<div>
<div purpose="g-label"></div>
<div purpose="g-bottom-label"></div>
</div>
</div>
<div purpose="g-platform">
<div purpose="g-icon"></div>
<div>
<div purpose="g-label"></div>
<div purpose="g-bottom-label"></div>
</div>
</div>
</div>
<div purpose="g-details">
<div purpose="g-table">
<div purpose="g-table-headings">
<div purpose="g-labels">
<div purpose="g-label-25"></div>
<div purpose="g-label-10"></div>
</div>
<div purpose="g-link"></div>
</div>
<div purpose="g-table-links">
<div purpose="g-label-25"></div>
<div purpose="g-label-10"></div>
</div>
<div purpose="g-table-body">
<div purpose="g-th">
<div purpose="g-td"><div purpose="g-label-25"></div></div>
<div purpose="g-td"><div purpose="g-label-25"></div></div>
<div purpose="g-td"><div purpose="g-label-25"></div></div>
</div>
<div purpose="g-tr">
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
</div>
<div purpose="g-tr">
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
</div>
<div purpose="g-tr">
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
</div>
<div purpose="g-tr">
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
</div>
<div purpose="g-tr">
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
</div>
<div purpose="g-tr">
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
</div>
<div purpose="g-tr">
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
</div>
<div purpose="g-tr">
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
</div>
<div purpose="g-tr">
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
</div>
</div>
<div purpose="g-table-pagination">
<div purpose="pagination-button">
<img class="d-flex" style="width: 6px; height: 10px;" src="/images/icon-chevron-fleet-black-50-10x17@2x.png" alt="a small chevron pointing downwards">
<div purpose="g-label-10"></div>
</div>
<div purpose="pagination-button">
<div purpose="g-label-25"></div>
<img class="d-flex" style="width: 6px; height: 10px;" src="/images/icon-chevron-fleet-black-50-10x17@2x.png" alt="a small chevron pointing downwards">
</div>
</div>
</div>
<div purpose="g-log">
<div purpose="g-log-header">
<div purpose="g-label-25"></div>
</div>
<div purpose="g-log-body">
<div purpose="left-column">
<div purpose="g-log-box"></div>
<div purpose="g-log-box"></div>
<div purpose="g-log-box"></div>
<div purpose="g-log-box"></div>
<div purpose="g-log-box"></div>
<div purpose="g-log-box"></div>
<div purpose="g-log-box"></div>
</div>
<div purpose="right-column">
<div purpose="g-log-item">
<div purpose="first-line">
<div purpose="g-label-25"></div>
<div purpose="g-label-10"></div>
<div purpose="g-label-25"></div>
<div purpose="g-label-10"></div>
</div>
<div purpose="second-line">
<div purpose="g-label-10"></div>
</div>
</div>
<div purpose="g-log-item">
<div purpose="first-line">
<div purpose="g-label-25"></div>
<div purpose="g-label-10"></div>
<div purpose="g-label-25"></div>
<div purpose="g-label-10"></div>
</div>
<div purpose="second-line">
<div purpose="g-label-10"></div>
</div>
</div>
<div purpose="g-log-item">
<div purpose="first-line">
<div purpose="g-label-25"></div>
<div purpose="g-label-10"></div>
<div purpose="g-label-25"></div>
<div purpose="g-label-10"></div>
</div>
<div purpose="second-line">
<div purpose="g-label-10"></div>
</div>
</div>
<div purpose="g-log-item">
<div purpose="first-line">
<div purpose="g-label-25"></div>
<div purpose="g-label-10"></div>
<div purpose="g-label-25"></div>
<div purpose="g-label-10"></div>
</div>
<div purpose="second-line">
<div purpose="g-label-10"></div>
</div>
</div>
<div purpose="g-log-item">
<div purpose="first-line">
<div purpose="g-label-25"></div>
<div purpose="g-label-10"></div>
<div purpose="g-label-25"></div>
<div purpose="g-label-10"></div>
</div>
<div purpose="second-line">
<div purpose="g-label-10"></div>
</div>
</div>
<div purpose="g-log-item">
<div purpose="first-line">
<div purpose="g-label-25"></div>
<div purpose="g-label-10"></div>
<div purpose="g-label-25"></div>
<div purpose="g-label-10"></div>
</div>
<div purpose="second-line">
<div purpose="g-label-10"></div>
</div>
</div>
<div purpose="g-log-item">
<div purpose="first-line">
<div purpose="g-label-25"></div>
<div purpose="g-label-10"></div>
<div purpose="g-label-25"></div>
<div purpose="g-label-10"></div>
</div>
<div purpose="second-line">
<div purpose="g-label-10"></div>
</div>
</div>
</div>
</div>
</div>
</div>
<div purpose="g-hosts-table">
<div purpose="g-table">
<div purpose="g-table-headings">
<div purpose="g-labels">
<div purpose="g-label-25"></div>
<div purpose="g-label-10"></div>
</div>
</div>
<div purpose="g-table-subheadings">
<div purpose="g-labels">
<div purpose="g-label-10"></div>
<div purpose="g-label-10"></div>
</div>
</div>
<div purpose="g-table-links">
<div purpose="g-label-25"></div>
<div purpose="g-label-10"></div>
</div>
<div purpose="g-table-body">
<div purpose="g-th">
<div purpose="g-td"><div purpose="g-label-25"></div></div>
<div purpose="g-td"><div purpose="g-label-25"></div></div>
</div>
<div purpose="g-tr">
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
</div>
<div purpose="g-tr">
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
</div>
<div purpose="g-tr">
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
</div>
<div purpose="g-tr">
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
</div>
<div purpose="g-tr">
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
</div>
<div purpose="g-tr">
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
</div>
<div purpose="g-tr">
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
</div>
<div purpose="g-tr">
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
</div>
<div purpose="g-tr">
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
</div>
</div>
<div purpose="g-table-pagination">
<div purpose="pagination-button">
<img class="d-flex" style="width: 6px; height: 10px;" src="/images/icon-chevron-fleet-black-50-10x17@2x.png" alt="a small chevron pointing downwards">
<div purpose="g-label-10"></div>
</div>
<div purpose="pagination-button">
<div purpose="g-label-25"></div>
<img class="d-flex" style="width: 6px; height: 10px;" src="/images/icon-chevron-fleet-black-50-10x17@2x.png" alt="a small chevron pointing downwards">
</div>
</div>
</div>
</div>
</div>
</div>
<div purpose="page-container" class="container">
<div class="d-flex" id="signupmodal" tabindex="-1" role="dialog">
<div class="petticoat"></div>
<div class="modal-dialog custom-width position-relative" role="document" purpose="modal-dialog" >
<div class="modal-content" purpose="modal-content" >
<div purpose="signup-modal">
<div purpose="logo-row">
<div purpose="modal-logo">
<img alt="Fleet logo" src="/images/logo-brandmark-32x32@2x.png">
</div>
<div purpose="close-button">
<button type="button" data-dismiss="modal" data-target="#signupmodal" aria-label="Close" purpose="modal-close-button" @click="clickGoBack()">&times;</button>
</div>
</div>
<h3 class="mb-0">Welcome to Fleet</h3>
<p class="mb-0">We just need a few details in order to get started.</p>
<div purpose="form-switch" class="d-flex flex-column">
<label purpose="form-option" class="form-control" :class="[formToDisplay === 'login' ? 'selected' : '']">
<input type="radio" v-model.trim="formToDisplay" value="login" @selected="switchForm('login')">
<span purpose="custom-radio"><span purpose="custom-radio-selected"></span></span>
I have an account
</label>
<label purpose="form-option" class="form-control" :class="[formToDisplay === 'signup' ? 'selected' : '']">
<input type="radio" v-model.trim="formToDisplay" value="signup" @selected="switchForm('signup')">
<span purpose="custom-radio"><span purpose="custom-radio-selected"></span></span>
I don't have an account
</label>
</div>
<ajax-form action="signup" purpose="modal-form" class="self-service-register" :syncing.sync="syncing" :cloud-error.sync="cloudError" :form-errors.sync="signupFormErrors" :form-data="signupFormData" :form-rules="signupFormRules" @submitted="submittedSignupForm()" v-if="formToDisplay === 'signup'">
<div class="form-group">
<label for="email">Email</label>
<input tabindex="1" type="email" class="form-control" :class="[formErrors.emailAddress ? 'is-invalid' : '']" v-model.trim="formData.emailAddress" autocomplete="email" focus-first>
<div class="invalid-feedback" v-if="formErrors.emailAddress">Please provide a valid email address.</div>
<label purpose="modal-form-label" for="email-address">Work email *</label>
<input tabindex="1" purpose="modal-form-input" class="form-control" id="email-address" :class="[signupFormErrors.emailAddress ? 'is-invalid' : '']" v-model.trim="signupFormData.emailAddress" @input="typeClearOneFormError('emailAddress')">
<div class="invalid-feedback" v-if="signupFormErrors.emailAddress" focus-first>This doesnt appear to be a valid email address</div>
</div>
<div class="form-group">
<label for="password">Password</label>
<input tabindex="2" type="password" class="form-control" :class="[formErrors.password ? 'is-invalid' : '']" v-model.trim="formData.password" autocomplete="current-password">
<div class="invalid-feedback" v-if="formErrors.password">Please enter your password.</div>
<label purpose="modal-form-label" for="password">Choose a password *</label>
<input tabindex="2" purpose="modal-form-input" class="form-control" id="password" type="password" :class="[signupFormErrors.password ? 'is-invalid' : '']" v-model.trim="signupFormData.password" autocomplete="new-password" @input="typeClearOneFormError('password')">
<div class="invalid-feedback" v-if="signupFormErrors.password === 'minLength'">Password too short.</div>
<div class="invalid-feedback" v-if="signupFormErrors.password === 'maxLength'">Password too long.</div>
<div class="invalid-feedback" v-if="signupFormErrors.password === 'custom'">Password does not meet requirements.</div>
<div class="invalid-feedback" v-if="signupFormErrors.password === 'required'">Please enter a password.</div>
<p purpose="modal-form-note" class="mt-2">Passwords must be 12-48 characters, with at least 1 number (e.g. 0 - 9) and 1 symbol (e.g. &*#).</p>
</div>
<cloud-error v-if="cloudError === 'noUser'">The email address provided doesn't match an existing account. Create an account <a href="/customers/register">here</a>.</cloud-error>
<div class="row">
<div class="col-12 col-sm-6 pr-sm-2">
<div class="form-group">
<label purpose="modal-form-label" for="first-name">First name *</label>
<input tabindex="4" purpose="modal-form-input" class="form-control" id="first-name" type="text" :class="[signupFormErrors.firstName ? 'is-invalid' : '']" v-model.trim="signupFormData.firstName" autocomplete="first-name" @input="typeClearOneFormError('firstName')">
<div class="invalid-feedback" v-if="signupFormErrors.firstName">Please enter your first name.</div>
</div>
</div>
<div class="col-12 col-sm-6 pl-sm-2">
<div class="form-group">
<label purpose="modal-form-label" for="last-name">Last name *</label>
<input tabindex="5" purpose="modal-form-input" class="form-control" id="last-name" type="text" :class="[signupFormErrors.lastName ? 'is-invalid' : '']" v-model.trim="signupFormData.lastName" autocomplete="last-name" @input="typeClearOneFormError('lastName')">
<div class="invalid-feedback" v-if="signupFormErrors.lastName">Please enter your last name.</div>
</div>
</div>
</div>
<cloud-error v-if="cloudError==='emailAlreadyInUse'">
This email is already linked to a Fleet account.<br> Please <a purpose="modal-form-link" @click="formToDisplay = 'login'">sign in</a> with your email and password.
</cloud-error>
<cloud-error v-if="cloudError === 'invalidEmailDomain'">
Please enter your work or school email address.
</cloud-error>
<blockquote purpose="tip" v-if="cloudError === 'invalidEmailDomain'">
<img src="/images/icon-info-16x16@2x.png" alt="An icon indicating that this section has important information">
<div class="d-block">
<p>Dont have a work email? Try a local demo of <a purpose="modal-form-link" href="/try-fleet">Fleet Free</a> instead.</p>
</div>
</blockquote>
<cloud-error purpose="cloud-error" v-if="cloudError && !['emailAlreadyInUse', 'invalidEmailDomain'].includes(cloudError)"></cloud-error>
<p purpose="modal-form-note">By signing up you agree to our <a purpose="modal-form-link" href="/legal/privacy">privacy policy</a> and <a purpose="modal-form-link" href="/terms">terms of service</a>.</p>
<ajax-button tabindex="6" purpose="modal-form-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 tabindex="7" purpose="modal-form-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>
<ajax-form class="w-100" action="login" purpose="modal-form" :syncing.sync="syncing" :cloud-error.sync="cloudError" :form-data="loginFormData" :form-rules="loginFormRules" :form-errors.sync="loginFormErrors" @submitted="submittedLoginForm()" v-else>
<div class="form-group">
<label purpose="modal-form-label" for="email">Email</label>
<input tabindex="1" type="email" purpose="modal-form-input" class="form-control" :class="[loginFormErrors.emailAddress ? 'is-invalid' : '']" v-model.trim="loginFormData.emailAddress" autocomplete="email" focus-first>
<div class="invalid-feedback" v-if="loginFormErrors.emailAddress">Please provide a valid email address.</div>
</div>
<div class="form-group">
<label purpose="modal-form-label" for="password">Password</label>
<input tabindex="2" type="password" purpose="modal-form-input" class="form-control" :class="[loginFormErrors.password ? 'is-invalid' : '']" v-model.trim="loginFormData.password" autocomplete="current-password">
<div class="invalid-feedback" v-if="loginFormErrors.password">Please enter your password.</div>
</div>
<cloud-error v-if="cloudError === 'noUser'">The email address provided doesn't match an existing account. Create an account <a purpose="modal-form-link" @click="formToDisplay = 'signup'">here</a>.</cloud-error>
<cloud-error v-else-if="cloudError === 'badCombo'">Somethings not quite right with your email or password.</cloud-error>
<cloud-error v-else-if="cloudError"></cloud-error>
<div class="pb-3">
<ajax-button tabindex="3" :syncing="syncing" spinner="true" purpose="submit-button" class="btn-primary mt-4 btn-lg btn-block">Sign in</ajax-button>
<ajax-button tabindex="3" :syncing="syncing" spinner="true" purpose="modal-form-submit-button" class="btn-primary mt-4 btn-lg btn-block">Sign in</ajax-button>
</div>
<span purpose="modal-form-note" class="text-center"><a purpose="modal-form-link" href="/customers/forgot-password">Forgot your password?</a></span>
</ajax-form>
<span class="text-center small"><a href="/customers/forgot-password">Forgot your password?</a></span>
</div>
</div>
<div purpose="quote-and-logos" class="mx-auto mx-lg-0">
<% if (['it-misc'].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">
Mad props to how easy making a deploy pkg of the agent was. I wish everyone made stuff that easy.
</p>
<div purpose="quote-author-info" class="d-flex flex-row align-items-center">
<div purpose="profile-picture">
<img alt="Wes Whetstone" src="/images/testimonial-author-wes-whetstone-48x48@2x.png">
</div>
<div class="d-flex flex-column align-self-top">
<p purpose="name" class="font-weight-bold m-0">Wes Whetstone</p>
<p purpose="job-title" class="m-0">Staff CPE</p>
</div>
</div>
</div>
<% } else if (['security-misc'].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 (['security-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>
<% } else { %>
<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">
We've been using Fleet for a few years at Stripe and we couldn't be happier. The fact that it's also open-source made it easy for us to try it out, customise it to our needs, and seamlessly integrate it into our existing environment.
</p>
<div purpose="quote-author-info" class="d-flex flex-row align-items-center">
<div purpose="profile-picture">
<img alt="Scott MacVicar" style="border-radius: 50%" src="/images/testimonial-author-scott-macvicar-100x100@2x.png">
</div>
<div class="d-flex flex-column align-self-top">
<p purpose="name" class="font-weight-bold m-0">Scott MacVicar</p>
<p purpose="job-title" class="m-0">Head of Developer Infrastructure &amp; Corporate Technology</p>
</div>
</div>
</div>
<% } %>
<div purpose="logos" class="flex-column flex-wrap align-items-center w-100">
<logo-carousel></logo-carousel>
</div>
</div>
</div>
-1
View File
@@ -117,6 +117,5 @@
<div purpose="bottom-gradient">
<parallax-city></parallax-city>
</div>
<signup-modal></signup-modal>
</div>
<%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %>
+2 -3
View File
@@ -9,7 +9,7 @@
<p>See every change, undo any error, repeat every success. Fleet and GitOps work together to optimize your endpoint management strategy.</p>
<div purpose="button-row">
<a purpose="cta-button" class="btn btn-primary" href="/contact">Get a demo</a>
<signup-button :is-logged-in="!! this.me"></signup-button>
<!-- <animated-arrow-button href="/try">Try it yourself</animated-arrow-button> -->
</div>
</div>
<div purpose="list-and-cta">
@@ -168,13 +168,12 @@
</div>
<div purpose="button-row">
<a purpose="cta-button" class="btn btn-primary" href="/contact">Get a demo</a>
<signup-button :is-logged-in="!! this.me"></signup-button>
<!-- <animated-arrow-button href="/try">Try it yourself</animated-arrow-button> -->
</div>
</div>
</div>
</div>
<%/* Cloud city banner */%>
<parallax-city></parallax-city>
<signup-modal></signup-modal>
</div>
<%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %>
+334 -2
View File
@@ -1,5 +1,337 @@
<div id="fleet-premium-trial" v-cloak>
<div purpose="fleet-ui-background">
<div purpose="g-header">
<div purpose="g-header-left">
<div purpose="g-header-logo">
<img alt="fleet-logo" src="/images/logo-brandmark-140x140@2x.png">
</div>
<div purpose="g-header-links">
<div purpose="g-link"></div>
<div purpose="g-link"></div>
<div purpose="g-link"></div>
<div purpose="g-link"></div>
<div purpose="g-link"></div>
</div>
</div>
<div purpose="g-header-right">
<div purpose="g-header-avatar">
<img alt="An avatar icon" src="/images/permanent/icon-avatar-default-gray-transparent-64x64@2x.png">
</div>
<div purpose="g-header-chevron">
<img class="d-flex" style="width: 16px; height: 16px;" src="/images/chevron-down-16x16@2x.png" alt="a small chevron pointing downwards">
</div>
</div>
</div>
<div purpose="g-content">
<div purpose="g-page-header">
<div></div>
</div>
<div purpose="g-team-select">
<div purpose="g-label">
</div>
<div purpose="g-select">
<div purpose="g-label"></div>
<img class="d-flex" style="width: 16px; height: 16px;" src="/images/chevron-down-16x16@2x.png" alt="a small chevron pointing downwards">
</div>
</div>
<div purpose="g-platforms">
<div purpose="g-platform">
<div purpose="g-icon"></div>
<div>
<div purpose="g-label"></div>
<div purpose="g-bottom-label"></div>
</div>
</div>
<div purpose="g-platform">
<div purpose="g-icon"></div>
<div>
<div purpose="g-label"></div>
<div purpose="g-bottom-label"></div>
</div>
</div>
<div purpose="g-platform">
<div purpose="g-icon"></div>
<div>
<div purpose="g-label"></div>
<div purpose="g-bottom-label"></div>
</div>
</div>
<div purpose="g-platform">
<div purpose="g-icon"></div>
<div>
<div purpose="g-label"></div>
<div purpose="g-bottom-label"></div>
</div>
</div>
<div purpose="g-platform">
<div purpose="g-icon"></div>
<div>
<div purpose="g-label"></div>
<div purpose="g-bottom-label"></div>
</div>
</div>
<div purpose="g-platform">
<div purpose="g-icon"></div>
<div>
<div purpose="g-label"></div>
<div purpose="g-bottom-label"></div>
</div>
</div>
</div>
<div purpose="g-details">
<div purpose="g-table">
<div purpose="g-table-headings">
<div purpose="g-labels">
<div purpose="g-label-25"></div>
<div purpose="g-label-10"></div>
</div>
<div purpose="g-link"></div>
</div>
<div purpose="g-table-links">
<div purpose="g-label-25"></div>
<div purpose="g-label-10"></div>
</div>
<div purpose="g-table-body">
<div purpose="g-th">
<div purpose="g-td"><div purpose="g-label-25"></div></div>
<div purpose="g-td"><div purpose="g-label-25"></div></div>
<div purpose="g-td"><div purpose="g-label-25"></div></div>
</div>
<div purpose="g-tr">
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
</div>
<div purpose="g-tr">
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
</div>
<div purpose="g-tr">
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
</div>
<div purpose="g-tr">
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
</div>
<div purpose="g-tr">
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
</div>
<div purpose="g-tr">
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
</div>
<div purpose="g-tr">
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
</div>
<div purpose="g-tr">
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
</div>
<div purpose="g-tr">
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
</div>
</div>
<div purpose="g-table-pagination">
<div purpose="pagination-button">
<img class="d-flex" style="width: 6px; height: 10px;" src="/images/icon-chevron-fleet-black-50-10x17@2x.png" alt="a small chevron pointing downwards">
<div purpose="g-label-10"></div>
</div>
<div purpose="pagination-button">
<div purpose="g-label-25"></div>
<img class="d-flex" style="width: 6px; height: 10px;" src="/images/icon-chevron-fleet-black-50-10x17@2x.png" alt="a small chevron pointing downwards">
</div>
</div>
</div>
<div purpose="g-log">
<div purpose="g-log-header">
<div purpose="g-label-25"></div>
</div>
<div purpose="g-log-body">
<div purpose="left-column">
<div purpose="g-log-box"></div>
<div purpose="g-log-box"></div>
<div purpose="g-log-box"></div>
<div purpose="g-log-box"></div>
<div purpose="g-log-box"></div>
<div purpose="g-log-box"></div>
<div purpose="g-log-box"></div>
</div>
<div purpose="right-column">
<div purpose="g-log-item">
<div purpose="first-line">
<div purpose="g-label-25"></div>
<div purpose="g-label-10"></div>
<div purpose="g-label-25"></div>
<div purpose="g-label-10"></div>
</div>
<div purpose="second-line">
<div purpose="g-label-10"></div>
</div>
</div>
<div purpose="g-log-item">
<div purpose="first-line">
<div purpose="g-label-25"></div>
<div purpose="g-label-10"></div>
<div purpose="g-label-25"></div>
<div purpose="g-label-10"></div>
</div>
<div purpose="second-line">
<div purpose="g-label-10"></div>
</div>
</div>
<div purpose="g-log-item">
<div purpose="first-line">
<div purpose="g-label-25"></div>
<div purpose="g-label-10"></div>
<div purpose="g-label-25"></div>
<div purpose="g-label-10"></div>
</div>
<div purpose="second-line">
<div purpose="g-label-10"></div>
</div>
</div>
<div purpose="g-log-item">
<div purpose="first-line">
<div purpose="g-label-25"></div>
<div purpose="g-label-10"></div>
<div purpose="g-label-25"></div>
<div purpose="g-label-10"></div>
</div>
<div purpose="second-line">
<div purpose="g-label-10"></div>
</div>
</div>
<div purpose="g-log-item">
<div purpose="first-line">
<div purpose="g-label-25"></div>
<div purpose="g-label-10"></div>
<div purpose="g-label-25"></div>
<div purpose="g-label-10"></div>
</div>
<div purpose="second-line">
<div purpose="g-label-10"></div>
</div>
</div>
<div purpose="g-log-item">
<div purpose="first-line">
<div purpose="g-label-25"></div>
<div purpose="g-label-10"></div>
<div purpose="g-label-25"></div>
<div purpose="g-label-10"></div>
</div>
<div purpose="second-line">
<div purpose="g-label-10"></div>
</div>
</div>
<div purpose="g-log-item">
<div purpose="first-line">
<div purpose="g-label-25"></div>
<div purpose="g-label-10"></div>
<div purpose="g-label-25"></div>
<div purpose="g-label-10"></div>
</div>
<div purpose="second-line">
<div purpose="g-label-10"></div>
</div>
</div>
</div>
</div>
</div>
</div>
<div purpose="g-hosts-table">
<div purpose="g-table">
<div purpose="g-table-headings">
<div purpose="g-labels">
<div purpose="g-label-25"></div>
<div purpose="g-label-10"></div>
</div>
</div>
<div purpose="g-table-subheadings">
<div purpose="g-labels">
<div purpose="g-label-10"></div>
<div purpose="g-label-10"></div>
</div>
</div>
<div purpose="g-table-links">
<div purpose="g-label-25"></div>
<div purpose="g-label-10"></div>
</div>
<div purpose="g-table-body">
<div purpose="g-th">
<div purpose="g-td"><div purpose="g-label-25"></div></div>
<div purpose="g-td"><div purpose="g-label-25"></div></div>
</div>
<div purpose="g-tr">
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
</div>
<div purpose="g-tr">
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
</div>
<div purpose="g-tr">
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
</div>
<div purpose="g-tr">
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
</div>
<div purpose="g-tr">
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
</div>
<div purpose="g-tr">
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
</div>
<div purpose="g-tr">
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
</div>
<div purpose="g-tr">
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
</div>
<div purpose="g-tr">
<div purpose="g-td"><div purpose="g-label-10"></div></div>
<div purpose="g-td"><div purpose="g-label-10"></div></div>
</div>
</div>
<div purpose="g-table-pagination">
<div purpose="pagination-button">
<img class="d-flex" style="width: 6px; height: 10px;" src="/images/icon-chevron-fleet-black-50-10x17@2x.png" alt="a small chevron pointing downwards">
<div purpose="g-label-10"></div>
</div>
<div purpose="pagination-button">
<div purpose="g-label-25"></div>
<img class="d-flex" style="width: 6px; height: 10px;" src="/images/icon-chevron-fleet-black-50-10x17@2x.png" alt="a small chevron pointing downwards">
</div>
</div>
</div>
</div>
</div>
</div>
@@ -11,7 +343,7 @@
<img alt="Fleet logo" src="/images/logo-brandmark-32x32@2x.png">
</div>
<div purpose="close-button">
<button type="button" class="position-absolute" data-dismiss="modal" aria-label="Close" purpose="modal-close-button" @click="closeModalAndRedirect()">&times;</button>
<button type="button" data-dismiss="modal" aria-label="Close" purpose="modal-close-button" @click="closeModalAndRedirect()">&times;</button>
</div>
</div>
<div purpose="content" v-if="!trialIsExpired">
@@ -66,7 +398,7 @@
<img alt="Fleet logo" src="/images/logo-brandmark-32x32@2x.png">
</div>
<div purpose="close-button">
<button type="button" class="position-absolute" data-dismiss="modal" aria-label="Close" purpose="modal-close-button" @click="closeModalAndRedirect()">&times;</button>
<button type="button" data-dismiss="modal" aria-label="Close" purpose="modal-close-button" @click="closeModalAndRedirect()">&times;</button>
</div>
</div>
<div purpose="content">
-1
View File
@@ -235,6 +235,5 @@
</div>
</div>
<parallax-city></parallax-city>
<signup-modal></signup-modal>
</div>
<%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %>
-1
View File
@@ -135,6 +135,5 @@
<p class="mb-0"><img alt="An arrow pointing up" class="d-inline" src="/images/icon-arrow-up-12x13@2x.png">Back to top</p>
</div>
</div>
<signup-modal></signup-modal>
</div>
<%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %>
+1 -2
View File
@@ -1453,7 +1453,7 @@
</h1>
<div purpose="button-row" style="margin-top: 40px;" class="d-flex flex-sm-row flex-column justify-content-center align-items-center mx-auto">
<a purpose="cta-button" href="/contact">Get a demo</a>
<signup-button :signed-in="this.me"></signup-button>
<!-- <animated-arrow-button href="/try">Try it yourself</animated-arrow-button> -->
</div>
</div>
</div>
@@ -1501,6 +1501,5 @@
<iframe width="560" height="315" src="https://www.youtube.com/embed/q1Tm3IBcx24?rel=0&autoplay=1" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
</modal>
<p style="opacity: 0; line-height: 0px; font-size: 0px; margin: 0;">537c652d-cb1a-440e-ae35-0f0bf5743e75</p>
<signup-modal></signup-modal>
</div>
<%- /* Expose locals as `window.SAILS_LOCALS` :: */ exposeLocalsToBrowser() %>
+1 -2
View File
@@ -410,6 +410,5 @@
</div>
</div>
</div>
<signup-modal></signup-modal>
</div>
<%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %>
<%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %>
@@ -30,6 +30,5 @@
</div>
</div>
</div>
<signup-modal></signup-modal>
</div>
<%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %>
-1
View File
@@ -144,6 +144,5 @@
</div>
</div>
</div>
<signup-modal></signup-modal>
</div>
<%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %>
-1
View File
@@ -18,6 +18,5 @@
</div>
</div>
</div>
<signup-modal></signup-modal>
</div>
<%- /* Expose locals as `window.SAILS_LOCALS` :: */ exposeLocalsToBrowser() %>
-1
View File
@@ -18,6 +18,5 @@
</div>
</div>
</div>
<signup-modal></signup-modal>
</div>
<%- /* Expose locals as `window.SAILS_LOCALS` :: */ exposeLocalsToBrowser() %>
-1
View File
@@ -96,6 +96,5 @@
</div>
</modal>
</div>
<signup-modal></signup-modal>
</div>
<%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %>
-1
View File
@@ -65,6 +65,5 @@
</div>
</div>
</div>
<signup-modal></signup-modal>
</div>
<%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %>
+2 -3
View File
@@ -28,7 +28,7 @@
<% }%>
<div purpose="button-row" class="d-flex flex-sm-row flex-column justify-content-start align-items-center">
<a purpose="cta-button" href="/contact">Get a demo</a>
<signup-button :is-logged-in="!! this.me"></signup-button>
<!-- <animated-arrow-button href="/try">Try it yourself</animated-arrow-button> -->
</div>
</div>
</div>
@@ -272,7 +272,7 @@
<h2><%= pagePersonalization==='eo-security'? 'Instrument your endpoints' : 'Talk to your computers'%></h2>
<div purpose="button-row" style="margin-top: 32px;" class="d-flex flex-sm-row flex-column justify-content-center align-items-center mx-auto">
<a purpose="cta-button" href="/contact">Get a demo</a>
<signup-button :is-logged-in="!! this.me"></signup-button>
<!-- <animated-arrow-button href="/try">Try it yourself</animated-arrow-button> -->
</div>
</div>
</div>
@@ -291,6 +291,5 @@
<modal purpose="video-modal" v-if="modal === 'calendar'" @close="closeModal()">
<iframe width="560" height="315" src="https://www.youtube.com/embed/nhufmzGUeNk?si=rtAF6sFZuA7PhYRS&autoplay=1" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
</modal>
<signup-modal></signup-modal>
</div>
<%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %>
-1
View File
@@ -77,6 +77,5 @@
</div>
</modal>
</div>
<signup-modal></signup-modal>
</div>
<%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %>
-1
View File
@@ -94,6 +94,5 @@
</div>
</modal>
</div>
<signup-modal></signup-modal>
</div>
<%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %>
-1
View File
@@ -89,6 +89,5 @@
</div>
</div>
</div>
<signup-modal></signup-modal>
</div>
<%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %>
-1
View File
@@ -106,7 +106,6 @@
</div>
</div>
</div>
<signup-modal></signup-modal>
</div>
-1
View File
@@ -61,6 +61,5 @@
</div>
</div>
</div>
<signup-modal></signup-modal>
</div>
<%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %>
-3
View File
@@ -50,8 +50,6 @@
</div>
</div>
<a purpose="card-button" class="btn btn-block btn-lg btn-primary mx-auto mb-0" href="/register">Get started</a>
<!-- <div>
</div> -->
</div>
</div>
</div>
@@ -405,6 +403,5 @@
</div>
</modal>
<p style="opacity: 0; line-height: 0px; font-size: 0px; margin: 0;">537c652d-cb1a-440e-ae35-0f0bf5743e75</p>
<signup-modal></signup-modal>
</div>
<%- /* Expose locals as `window.SAILS_LOCALS` :: */ exposeLocalsToBrowser() %>
-1
View File
@@ -68,6 +68,5 @@
</div>
</div>
</div>
<signup-modal></signup-modal>
</div>
<%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %>
-1
View File
@@ -79,7 +79,6 @@
</div>
</div>
</div>
<signup-modal></signup-modal>
</div>
-1
View File
@@ -39,6 +39,5 @@
</div>
</div>
</div>
<signup-modal></signup-modal>
</div>
<%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %>
-1
View File
@@ -94,6 +94,5 @@
</div>
</modal>
</div>
<signup-modal></signup-modal>
</div>
<%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %>
+3 -3
View File
@@ -7,7 +7,7 @@
<p purpose="hero-text">Pick from a curated software catalog or upload your own custom packages. Configure custom installation scripts if you need or let Fleet do it for you.</p>
<div purpose="button-row" class="d-flex justify-content-start">
<a class="btn btn-primary" purpose="contact-button" href="/contact">Get a demo</a>
<signup-button :is-logged-in="!! this.me"></signup-button>
<!-- <animated-arrow-button href="/try">Try it yourself</animated-arrow-button> -->
</div>
</div>
<div purpose="hero-slides">
@@ -220,12 +220,12 @@
<h2>Manage software consistently</h2>
<div purpose="button-row" class="d-flex justify-content-center align-items-center mx-auto">
<a class="btn btn-primary" purpose="contact-button" href="/contact">Get a demo</a>
<signup-button :is-logged-in="!! this.me"></signup-button>
<!-- <animated-arrow-button href="/try">Try it yourself</animated-arrow-button> -->
</div>
</div>
</div>
<%/* Cloud city banner */%>
<parallax-city></parallax-city>
<signup-modal></signup-modal>
</div>
<%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %>
-1
View File
@@ -62,6 +62,5 @@
</div>
</div>
<signup-modal></signup-modal>
</div>
<%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %>
+1 -2
View File
@@ -235,7 +235,7 @@
</div>
<div purpose="button-row" class="d-flex flex-sm-row flex-column justify-content-center align-items-center mx-auto">
<a purpose="cta-button" href="/contact">Get a demo</a>
<signup-button :is-logged-in="!! this.me"></signup-button>
<!-- <animated-arrow-button href="/try">Try it yourself</animated-arrow-button> -->
</div>
</div>
</div>
@@ -250,6 +250,5 @@
<iframe width="560" height="315" :src="'https://www.youtube.com/embed/'+video.embedId+'?rel=0'" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture;" allowfullscreen></iframe>
</modal>
</div>
<signup-modal></signup-modal>
</div>
<%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %>
-1
View File
@@ -331,7 +331,6 @@
<div purpose="bottom-gradient">
<parallax-city></parallax-city>
</div>
<signup-modal></signup-modal>
<modal purpose="video-modal" v-if="modal === 'fleet-in-three-minutes'" @close="closeModal()">
<iframe width="560" height="315" src="https://www.youtube.com/embed/mHFr-tBy3h8?rel=0&autoplay=1" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
</modal>
-1
View File
@@ -147,6 +147,5 @@
<% } %>
</div>
</modal>
<signup-modal></signup-modal>
</div>
<%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %>