PulseCheck Settings - Done
6 min
View Live Example
Tabs
HTML
<section class="section">
<div class="w-layout-blockcontainer body-container w-container">
<div class="page-header">
<div class="w-layout-grid grid-2">
<div class="page-header-left">
<div class="breadcrumbs">
<a href="{/pulsechecks}" class="breadcrumb">PulseChecks</a>
<div class="breadcrumb-divider">/</div>
<a href="{/pulsechecks/id/dashboard}" class="breadcrumb">{PulseCheck name e.g. Client happiness}</a>
<div class="breadcrumb-divider">/</div>
<div class="breadcrumb">Settings</div>
</div>
<div class="tab-heading-container-for-button">
<div>
<h1>{PulseCheck name}: Settings</h1>
<div class="subheading">Configure and Manage Your PulseCheck Survey</div>
</div>
<div>
<a href="{/pulsechecks/id/dashboard}" class="button w-inline-block">
<div class="icon _16">
<svg width="16" height="16" fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 32 32">
<polygon points="4 20 4 22 8.586 22 2 28.586 3.414 30 10 23.414 10 28 12 28 12 20 4 20"><rect x="24.0001" y="21" width="2" height="5"></rect><rect x="20.0001" y="16" width="2" height="10"></rect><rect x="16" y="18" width="2" height="8"></rect><path d="M28,2H4A2.002,2.002,0,0,0,2,4V16H4V13H28.001l.001,15H16v2H28a2.0027,2.0027,0,0,0,2-2V4A2.0023,2.0023,0,0,0,28,2ZM12,11H4V4h8Zm2,0V4H28l.0007,7Z"></path></polygon></svg>
</div>
<div>View PulseCheck</div>
</a>
</div>
</div>
</div>
</div>
</div>
<div class="tabs-wrapper">
<div class="tabs-container">
<div data-current="PulseCheck" data-easing="ease" data-duration-in="300" data-duration-out="100" class="tabs w-tabs">
<div class="tabs-menu w-tab-menu">
<a data-w-tab="PulseCheck" class="tab w-inline-block w-tab-link w--current">
<div class="tab-icon">
<svg fill="currentColor" width="32" height="32" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 32 32"><path d="M30,24V22H27.8989a4.9678,4.9678,0,0,0-.7319-1.7529l1.49-1.49-1.414-1.414-1.49,1.49A4.9678,4.9678,0,0,0,24,18.1011V16H22v2.1011a4.9678,4.9678,0,0,0-1.7529.7319l-1.49-1.49-1.414,1.414,1.49,1.49A4.9678,4.9678,0,0,0,18.1011,22H16v2h2.1011a4.9678,4.9678,0,0,0,.7319,1.7529l-1.49,1.49,1.414,1.414,1.49-1.49A4.9678,4.9678,0,0,0,22,27.8989V30h2V27.8989a4.9678,4.9678,0,0,0,1.7529-.7319l1.49,1.49,1.414-1.414-1.49-1.49A4.9678,4.9678,0,0,0,27.8989,24Zm-7,2a3,3,0,1,1,3-3A3.0033,3.0033,0,0,1,23,26Z"></path><path d="M25,5H22V4a2.0058,2.0058,0,0,0-2-2H12a2.0058,2.0058,0,0,0-2,2V5H7A2.0058,2.0058,0,0,0,5,7V28a2.0058,2.0058,0,0,0,2,2h7V28H7V7h3v3H22V7h3v6h2V7A2.0058,2.0058,0,0,0,25,5ZM20,8H12V4h8Z"></path></svg>
</div>
<div class="tab-name">PulseCheck</div>
</a>
<a data-w-tab="Respondents" class="tab w-inline-block w-tab-link">
<div class="tab-icon">
<svg fill="currentColor" width="32" height="32" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 32 32"><path d="M26,14H24v2h2a3.0033,3.0033,0,0,1,3,3v4h2V19A5.0058,5.0058,0,0,0,26,14Z" transform="translate(0 0)"></path><path d="M24,4a3,3,0,1,1-3,3,3,3,0,0,1,3-3m0-2a5,5,0,1,0,5,5A5,5,0,0,0,24,2Z" transform="translate(0 0)"></path><path d="M23,30H21V28a3.0033,3.0033,0,0,0-3-3H14a3.0033,3.0033,0,0,0-3,3v2H9V28a5.0059,5.0059,0,0,1,5-5h4a5.0059,5.0059,0,0,1,5,5Z" transform="translate(0 0)"></path><path d="M16,13a3,3,0,1,1-3,3,3,3,0,0,1,3-3m0-2a5,5,0,1,0,5,5A5,5,0,0,0,16,11Z" transform="translate(0 0)"></path><path d="M8,14H6a5.0059,5.0059,0,0,0-5,5v4H3V19a3.0033,3.0033,0,0,1,3-3H8Z" transform="translate(0 0)"></path><path d="M8,4A3,3,0,1,1,5,7,3,3,0,0,1,8,4M8,2a5,5,0,1,0,5,5A5,5,0,0,0,8,2Z" transform="translate(0 0)"></path></svg>
</div>
<div class="tab-name">Audience</div>
</a>
<a data-w-tab="Review Platforms" class="tab w-inline-block w-tab-link">
<div class="tab-icon w-embed">
<svg fill="currentColor" width="32" height="32" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 32 32"><rect x="18" y="26" width="8" height="2"></rect><rect x="18" y="22" width="12" height="2"></rect><rect x="18" y="18" width="12" height="2"></rect><polygon points="20.549 11.217 16 2 11.451 11.217 1.28 12.695 8.64 19.87 6.902 30 14 26.269 14 24.009 9.559 26.344 10.611 20.208 10.789 19.171 10.036 18.438 5.578 14.091 11.739 13.196 12.779 13.045 13.245 12.102 16 6.519 18.755 12.102 19.221 13.045 20.261 13.196 27.715 14.281 28 12.3 20.549 11.217"></polygon></svg>
</div>
<div class="tab-name">Review Platforms</div>
</a>
</div>
<div class="tabs-content w-tab-content">
<!-- Tabs go here -->
</div>
</div>
</div>
</div>
<div class="page-footer">
<div id="poweredBy" class="powered-by">
<p class="paragraph">Powered by <a href="https://www.userfirstdigital.com">User First</a>
</p>
</div>
<div class="legal-links">
<a href="#">Privacy</a>
<a href="#">Terms of Use</a>
</div>
</div>
</div>
</section>
Tabs
The PulseCheck Settings screen contains a series of Tabs
Scripts
Toggle
Uses Toggle v2
Rounded Corner Slider
<script>
// Rounded Corner Slider
document.addEventListener('DOMContentLoaded', function() {
var slider = document.getElementById('radius-slider');
var example = document.getElementById('radius-example');
// Additional classes to update
var additionalClasses = [
'.pulsecheck-preview',
'.pulsecheck-question-option',
'.pulsecheck-question-comment',
'.referral-question-option',
'.pulsecheck-complete-button'
];
if (slider && example) {
function updateRadius() {
var radius = parseFloat(slider.value).toFixed(2);
// Update the example element
example.style.borderRadius = radius + 'rem';
// Update all elements with the additional classes
additionalClasses.forEach(function(className) {
var elements = document.querySelectorAll(className);
elements.forEach(function(element) {
element.style.borderRadius = radius + 'rem';
});
});
}
// Initial update
updateRadius();
// Add event listeners
slider.addEventListener('input', updateRadius);
slider.addEventListener('change', updateRadius);
}
var arrowSVG = `
<svg width="16" height="16" fill="currentColor"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<polygon points="22 6 22 8 9.41 8 26 24.59 24.59 26 8 9.41 8 22 6 22 6 6 22 6" />
</svg>
`;
var corners = [
{ top: '0.5rem', left: '0.5rem', rotation: '0deg' },
{ top: '0.5rem', right: '0.5rem', rotation: '90deg' },
{ bottom: '0.5rem', right: '0.5rem', rotation: '180deg' },
{ bottom: '0.5rem', left: '0.5rem', rotation: '270deg' }
];
if (example) {
corners.forEach(function(corner) {
var arrowDiv = document.createElement('div');
arrowDiv.classList.add('corner-arrow');
arrowDiv.innerHTML = arrowSVG;
if (corner.top) arrowDiv.style.top = corner.top;
if (corner.right) arrowDiv.style.right = corner.right;
if (corner.bottom) arrowDiv.style.bottom = corner.bottom;
if (corner.left) arrowDiv.style.left = corner.left;
arrowDiv.style.transform = 'rotate(' + corner.rotation + ')';
example.appendChild(arrowDiv);
});
}
});
</script>
<style>
input[type="range"] {
-webkit-appearance: none;
width: 200px;
background: transparent;
margin: 0;
}
input[type="range"]:focus {
outline: none;
}
/* Chrome, Safari, Opera */
input[type="range"]::-webkit-slider-runnable-track {
width: 100%;
height: 8px;
background: var(--brand-colors--gray-300);
border-radius: 5px;
cursor: pointer;
}
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
height: 20px;
width: 20px;
margin-top: -6px;
background: var(--brand-colors--brand-600);
border: 1px solid var(--brand-colors--brand-600);
border-radius: 50%;
cursor: pointer;
transition: background 0.3s;
}
input[type="range"]::-webkit-slider-thumb:hover {
background: var(--brand-colors--brand-700);
}
/* Firefox */
input[type="range"]::-moz-range-track {
width: 100%;
height: 8px;
background: var(--brand-colors--gray-300);
border-radius: 5px;
cursor: pointer;
}
input[type="range"]::-moz-range-thumb {
height: 20px;
width: 20px;
background: var(--brand-colors--brand-600);
border: 1px solid var(--brand-colors--brand-600);
border-radius: 50%;
cursor: pointer;
transition: background 0.3s;
}
input[type="range"]::-moz-range-thumb:hover {
background: var(--brand-colors--brand-700);
}
/* Internet Explorer */
input[type="range"]::-ms-track {
width: 100%;
height: 8px;
background: transparent;
border-color: transparent;
color: transparent;
cursor: pointer;
}
input[type="range"]::-ms-fill-lower {
background: var(--brand-colors--gray-300);
border-radius: 5px;
}
input[type="range"]::-ms-fill-upper {
background: var(--brand-colors--gray-300);
border-radius: 5px;
}
input[type="range"]::-ms-thumb {
height: 20px;
width: 20px;
background: var(--brand-colors--brand-600);
border: 1px solid var(--brand-colors--brand-600);
border-radius: 50%;
cursor: pointer;
transition: background 0.3s;
}
input[type="range"]::-ms-thumb:hover {
background: var(--brand-colors--brand-700);
}
.corner-arrow {
position: absolute;
width: 16px;
height: 16px;
transform-origin: center center;
}
</style>Color Picker
<script>
/**
* Enhanced Color Picker with Class Update Functionality
*
* Finds all color picker groups on the page and initializes them.
* Supports updating CSS classes when color value changes.
*
* Format for data-colorpicker-update-classes attribute:
* - Basic: "element.property"
* - With opacity: "element.property:0.5"
* - Hover state: "element:hover.property"
* - Focus state: "element:focus.property"
* - With modifiers: "element.modifier.property"
* - Multiple updates: "element1.property1, element2.property2"
*
* Supported properties:
* - color
* - backgroundcolor (converts to background-color)
* - bordercolor (converts to border-color)
* - outlinecolor (converts to outline-color)
* - placeholder (updates text placeholder color for inputs)
*/
document.addEventListener('DOMContentLoaded', function() {
// Find all color picker groups on the page
const colorPickerGroups = document.querySelectorAll('.color-picker');
colorPickerGroups.forEach(function(group) {
try {
// Find inputs by type within this group
const colorInput = group.querySelector('input[type="color"]');
const textInput = group.querySelector('input[type="text"]');
if (!colorInput || !textInput) return; // Skip if missing required inputs
// Get initial color from data attribute or default to black
let hexValue = group.getAttribute('data-colorpicker-value') || '#000000';
// Ensure hex value is properly formatted
if (!hexValue.startsWith('#')) {
hexValue = '#' + hexValue;
}
// Set initial values
colorInput.value = hexValue;
textInput.value = hexValue;
// Store rules by selector for opacity tracking
const ruleRegistry = {};
/**
* Updates CSS classes based on the color picker value
* @param {string} color - The hex color value
*/
function updateClassColors(color) {
try {
const updateClassesAttr = group.getAttribute('data-colorpicker-update-classes');
if (!updateClassesAttr) return;
// Parse the attribute value
const classUpdates = updateClassesAttr.split(',').map(item => item.trim());
// Create a unique ID for these rules based on the group
const groupId = group.id || 'color-picker-' + Math.random().toString(36).substr(2, 9);
classUpdates.forEach(function(update) {
try {
// Initialize variables
let selector = '';
let property = '';
let opacityValue = 1;
let propertyWithoutOpacity = update;
// First check if the update includes an opacity value at the end
if (update.includes(':')) {
const parts = update.split(':');
const lastPart = parts[parts.length - 1];
// If the last part is a valid opacity value (0-1)
if (!isNaN(parseFloat(lastPart)) && parseFloat(lastPart) >= 0 && parseFloat(lastPart) <= 1) {
opacityValue = parseFloat(lastPart);
// Remove the opacity part from the update string
propertyWithoutOpacity = parts.slice(0, -1).join(':');
}
}
// Now parse the selector and property
if (propertyWithoutOpacity.includes(':hover.')) {
// Format: class:hover.property
const parts = propertyWithoutOpacity.split(':hover.');
selector = '.' + parts[0] + ':hover';
property = parts[1];
} else if (propertyWithoutOpacity.includes(':focus.')) {
// Format: class:focus.property
const parts = propertyWithoutOpacity.split(':focus.');
selector = '.' + parts[0] + ':focus';
property = parts[1];
} else if (propertyWithoutOpacity.includes('.')) {
// Split by dot
const parts = propertyWithoutOpacity.split('.');
// The property is always the last part
property = parts.pop();
// Check if we have CSS property names that might be mistaken as part of the selector
const cssProperties = ['color', 'backgroundcolor', 'bordercolor', 'outlinecolor', 'placeholder'];
if (parts.length > 0 && cssProperties.includes(property.toLowerCase())) {
// Create the selector by joining all parts but the last one
selector = '.' + parts.join('.');
} else {
return; // Skip if format is invalid
}
} else {
return; // Skip if format is invalid
}
// Convert property to standard CSS property name
let cssProperty = property.toLowerCase();
// Convert camelCase to kebab-case for CSS properties
if (cssProperty === 'backgroundcolor') {
cssProperty = 'background-color';
} else if (cssProperty === 'bordercolor') {
cssProperty = 'border-color';
} else if (cssProperty === 'outlinecolor') {
cssProperty = 'outline-color';
} else if (cssProperty === 'placeholder') {
// Special case for placeholder text color
cssProperty = 'color'; // We'll use this for the rule content
}
// Create a rule ID for this specific rule (for update tracking)
const ruleId = `${groupId}-${selector.replace(/[^a-z0-9]/gi, '-')}-${cssProperty}`;
// Apply opacity to color if it's a background-color property
let finalColor = color;
if (cssProperty === 'background-color' && opacityValue !== 1) {
// Convert hex to rgb
const r = parseInt(color.slice(1, 3), 16);
const g = parseInt(color.slice(3, 5), 16);
const b = parseInt(color.slice(5, 7), 16);
finalColor = `rgba(${r}, ${g}, ${b}, ${opacityValue})`;
}
// Store the selector and opacity for future reference
if (!ruleRegistry[selector]) {
ruleRegistry[selector] = {};
}
ruleRegistry[selector].opacity = opacityValue;
// Special handling for placeholder
if (property.toLowerCase() === 'placeholder') {
// For placeholder text, we need to create rules for all browser variants
const placeholderSelectors = [
`${selector}::placeholder`,
`${selector}::-webkit-input-placeholder`,
`${selector}::-moz-placeholder`,
`${selector}:-ms-input-placeholder`,
`${selector}:-moz-placeholder`
];
// Create a rule for each placeholder selector variant
placeholderSelectors.forEach(function(placeholderSelector) {
const placeholderRuleId = `${groupId}-${placeholderSelector.replace(/[^a-z0-9]/gi, '-')}-color`;
// Apply opacity if needed
let placeholderColor = color;
if (opacityValue !== 1) {
const r = parseInt(color.slice(1, 3), 16);
const g = parseInt(color.slice(3, 5), 16);
const b = parseInt(color.slice(5, 7), 16);
placeholderColor = `rgba(${r}, ${g}, ${b}, ${opacityValue})`;
}
// Create or update rule
const existingRule = document.getElementById(placeholderRuleId);
if (existingRule) {
existingRule.textContent = `${placeholderSelector} { color: ${placeholderColor} !important; }`;
} else {
const ruleElement = document.createElement('style');
ruleElement.id = placeholderRuleId;
ruleElement.textContent = `${placeholderSelector} { color: ${placeholderColor} !important; }`;
document.head.appendChild(ruleElement);
}
});
return; // Skip the regular rule creation below
}
// Check if we already have a style rule for this
const existingRule = document.getElementById(ruleId);
if (existingRule) {
// Update existing rule
existingRule.textContent = `${selector} { ${cssProperty}: ${finalColor} !important; }`;
} else {
// Create a new style element for this specific rule
const ruleElement = document.createElement('style');
ruleElement.id = ruleId;
ruleElement.textContent = `${selector} { ${cssProperty}: ${finalColor} !important; }`;
document.head.appendChild(ruleElement);
}
} catch (updateError) {
// Silently handle individual update errors to not block other updates
}
});
} catch (error) {
// Silently handle errors in the update process
}
}
// Apply initial color update
updateClassColors(hexValue);
// Update text input and classes when color picker changes
colorInput.addEventListener('input', function() {
textInput.value = this.value;
group.setAttribute('data-colorpicker-value', this.value);
updateClassColors(this.value);
});
// Update color picker and classes when text input changes
textInput.addEventListener('input', function() {
let value = this.value;
// Add # if missing
if (value && value.charAt(0) !== '#') {
value = '#' + value;
}
// Only update if valid hex color
if (/^#([0-9A-F]{3}){1,2}$/i.test(value)) {
colorInput.value = value;
group.setAttribute('data-colorpicker-value', value);
updateClassColors(value);
}
});
// Clean up text input value on blur
textInput.addEventListener('blur', function() {
try {
// Revert to color input's value if text is invalid
if (!/^#([0-9A-F]{3}){1,2}$/i.test(this.value)) {
this.value = colorInput.value;
}
// Ensure lowercase for consistency
this.value = this.value.toLowerCase();
// Update classes one more time in case the value was fixed
updateClassColors(this.value);
} catch (error) {
// Silently handle errors
}
});
} catch (error) {
// Silently handle errors for robustness
}
});
});
</script>