mirror of
https://github.com/baz-scm/awesome-reviewers.git
synced 2025-08-20 18:58:52 +03:00
82 lines
223 KiB
JSON
82 lines
223 KiB
JSON
[
|
|
{
|
|
"discussion_id": "2204234815",
|
|
"pr_number": 33948,
|
|
"pr_file": "posthog/templates/surveys/public_survey.html",
|
|
"created_at": "2025-07-14T08:41:06+00:00",
|
|
"commented_code": "+<!DOCTYPE html>\n+<html lang=\"en\">\n+\n+<head>\n+ <meta charset=\"UTF-8\">\n+ <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n+ <title>{{ name }}</title>\n+ <meta name=\"description\" content=\"Take our survey: {{ name }}\">\n+ <style>\n+ /* CSS Variables */\n+ :root {\n+ --ph-survey-font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', Helvetica, Arial, sans-serif;\n+ --ph-survey-border-color: #e5e7eb;\n+ --ph-survey-border-radius: 8px;\n+ --ph-survey-card-border-radius: 16px;\n+ --ph-survey-body-background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n+ --ph-survey-header-background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n+ --ph-survey-header-text-color: white;\n+ --ph-survey-background-color: #ffffff;\n+ --ph-survey-text-primary-color: #111827;\n+ --ph-survey-text-subtle-color: #6b7280;\n+ --ph-survey-input-background: #ffffff;\n+ --ph-survey-submit-button-color: #2563eb;\n+ --ph-survey-submit-button-text-color: white;\n+ --ph-survey-rating-button-color: #f8fafc;\n+ --ph-survey-rating-active-bg-color: #2563eb;\n+ --ph-survey-rating-button-text-color: #374151;\n+ --ph-survey-rating-button-active-text-color: white;\n+ --ph-survey-disabled-button-opacity: 0.6;\n+ --ph-survey-focus-ring: 0 0 0 3px rgba(37, 99, 235, 0.1);\n+ --ph-survey-box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);\n+ }\n+\n+ * {\n+ box-sizing: border-box;\n+ }\n+\n+ /* Base Layout */\n+ body {\n+ font-family: var(--ph-survey-font-family);\n+ margin: 0;\n+ padding: 0;\n+ background: var(--ph-survey-body-background);\n+ min-height: 100vh;\n+ line-height: 1.6;\n+ color: var(--ph-survey-text-primary-color);\n+ font-size: 16px;\n+ -webkit-font-smoothing: antialiased;\n+ }\n+\n+ .main-container {\n+ min-height: 100vh;\n+ display: flex;\n+ align-items: center;\n+ justify-content: center;\n+ padding: 1rem;\n+ box-sizing: border-box;\n+ }\n+\n+ .survey-card {\n+ background: white;\n+ border-radius: var(--ph-survey-card-border-radius);\n+ box-shadow: var(--ph-survey-box-shadow);\n+ max-width: 720px;\n+ width: 100%;\n+ overflow: hidden;\n+ max-height: 90vh;\n+ display: flex;\n+ flex-direction: column;\n+ animation: slideUp 0.6s ease-out;\n+ }\n+\n+ /* Survey Header */\n+ .survey-header {\n+ background: var(--ph-survey-header-background);\n+ color: var(--ph-survey-header-text-color);\n+ padding: 1.75rem 2rem 1.5rem;\n+ text-align: center;\n+ flex-shrink: 0;\n+ }\n+\n+ .survey-title {\n+ font-size: 1.75rem;\n+ font-weight: 700;\n+ margin: 0;\n+ }\n+\n+ .survey-description {\n+ font-size: 1rem;\n+ margin: 0;\n+ opacity: 0.9;\n+ line-height: 1.4;\n+ }\n+\n+ /* Survey Content */\n+ .survey-content {\n+ flex: 1;\n+ display: flex;\n+ flex-direction: column;\n+ min-height: 0;\n+ }\n+\n+ .survey-box {\n+ display: flex;\n+ flex-direction: column;\n+ gap: 1rem;\n+ flex: 1;\n+ min-height: 0;\n+ }\n+\n+ .bottom-section {\n+ display: flex;\n+ flex-direction: column;\n+ gap: 0.75rem;\n+ }\n+\n+ .survey-form,\n+ .thank-you-message {\n+ width: 100%;\n+ margin: 0;\n+ border: none;\n+ border-radius: 0;\n+ box-shadow: none;\n+ background: white;\n+ padding: 1.5rem 2rem;\n+ display: flex;\n+ flex-direction: column;\n+ justify-content: center;\n+ min-height: 0;\n+ }\n+\n+ /* Question Styling */\n+ .survey-question {\n+ font-size: 1.25rem;\n+ font-weight: 600;\n+ color: var(--ph-survey-text-primary-color);\n+ line-height: 1.4;\n+ margin: 0;\n+ }\n+\n+ .survey-question-description {\n+ font-size: 1rem;\n+ color: var(--ph-survey-text-subtle-color);\n+ margin-top: 0.25rem;\n+ margin-bottom: 1.25rem;\n+ }\n+\n+ .question-container,\n+ .thank-you-message {\n+ display: flex;\n+ flex-direction: column;\n+ justify-content: center;\n+ gap: 8px;\n+ }\n+\n+ .response-choice {\n+ display: flex;\n+ gap: 8px;\n+ align-items: center;\n+ }\n+\n+\n+ /* Input Styling */\n+ textarea,\n+ input[type='text'] {\n+ border: 2px solid var(--ph-survey-border-color);\n+ border-radius: var(--ph-survey-border-radius);\n+ padding: 1rem;\n+ font-size: 1rem;\n+ line-height: 1.5;\n+ transition: all 0.2s ease;\n+ background: var(--ph-survey-input-background);\n+ color: var(--ph-survey-text-primary-color);\n+ width: 100%;\n+ font-family: var(--ph-survey-font-family);\n+ }\n+\n+ textarea:focus,\n+ input[type='text']:focus {\n+ outline: none;\n+ border-color: var(--ph-survey-rating-active-bg-color);\n+ box-shadow: var(--ph-survey-focus-ring);\n+ }\n+\n+ textarea:hover:not(:focus),\n+ input[type='text']:hover:not(:focus) {\n+ border-color: var(--ph-survey-rating-active-bg-color);\n+ }\n+\n+ /* Multiple Choice Options */\n+ .multiple-choice-options {\n+ display: flex;\n+ flex-direction: column;\n+ gap: 0.625rem;\n+ flex: 1;\n+ justify-content: flex-start;\n+ overflow-y: auto;\n+ max-height: 400px;\n+ padding-right: 0.5rem;\n+ margin: 0;\n+ padding-left: 0;\n+ border: none;\n+ }\n+\n+ /* Fieldset styling */\n+ fieldset {\n+ border: none;\n+ margin: 0;\n+ padding: 0;\n+ }\n+\n+ .multiple-choice-options label {\n+ border: 2px solid var(--ph-survey-border-color);\n+ border-radius: var(--ph-survey-border-radius);\n+ padding: 0.875rem 1.25rem;\n+ cursor: pointer;\n+ transition: all 0.2s ease;\n+ background: white;\n+ font-size: 1rem;\n+ min-height: 56px;\n+ display: flex;\n+ align-items: center;\n+ gap: 12px;\n+ flex-shrink: 0;\n+ color: var(--ph-survey-text-primary-color);\n+ font-family: var(--ph-survey-font-family);\n+ }\n+\n+ .choice-option-open {\n+ flex-wrap: wrap;\n+ }\n+\n+ .multiple-choice-options label:hover:not(:has(input:checked)) {\n+ border-color: #d1d5db;\n+ background: #f9fafb;\n+ }\n+\n+ .multiple-choice-options label:has(input:checked) {\n+ border-color: var(--ph-survey-rating-active-bg-color);\n+ background: #eff6ff;\n+ }\n+\n+ .multiple-choice-options input[type='checkbox'],\n+ .multiple-choice-options input[type='radio'] {\n+ appearance: none;\n+ width: 1rem;\n+ height: 1rem;\n+ background: var(--ph-survey-input-background);\n+ border: 1.5px solid var(--ph-survey-border-color);\n+ cursor: pointer;\n+ border-radius: 3px;\n+ flex-shrink: 0;\n+ transition: all 0.2s ease;\n+ position: relative;\n+ margin: 0;\n+ }\n+\n+ .multiple-choice-options input[type='radio'] {\n+ border-radius: 50%;\n+ }\n+\n+ .multiple-choice-options input[type='checkbox']:hover,\n+ .multiple-choice-options input[type='radio']:hover {\n+ border-color: var(--ph-survey-rating-active-bg-color);\n+ transform: scale(1.05);\n+ }\n+\n+ .multiple-choice-options input[type='checkbox']:checked,\n+ .multiple-choice-options input[type='radio']:checked {\n+ background: var(--ph-survey-rating-active-bg-color);\n+ border-color: var(--ph-survey-rating-active-bg-color);\n+ }\n+\n+ .multiple-choice-options input[type='checkbox']:checked::after {\n+ content: '';\n+ position: absolute;\n+ left: 4px;\n+ width: 4px;\n+ height: 8px;\n+ border: solid white;\n+ border-width: 0 2px 2px 0;\n+ transform: rotate(45deg);\n+ }\n+\n+ .multiple-choice-options input[type='radio']:checked::after {\n+ content: '';\n+ position: absolute;\n+ left: 3.5px;\n+ top: 3.5px;\n+ width: 6px;\n+ height: 6px;\n+ border-radius: 50%;\n+ background: white;\n+ }\n+\n+ /* Rating Styles */\n+ .rating-text {\n+ display: flex;\n+ flex-direction: row;\n+ font-size: 0.8rem;\n+ justify-content: space-between;\n+ opacity: 0.7;\n+ }\n+\n+ .rating-options-number {\n+ display: grid;\n+ grid-auto-columns: 1fr;\n+ grid-auto-flow: column;\n+ border-radius: var(--ph-survey-border-radius);\n+ overflow: hidden;\n+ border: 2px solid var(--ph-survey-border-color);\n+ }\n+\n+ .ratings-number {\n+ padding: 0.875rem 0;\n+ border: none;\n+ background-color: var(--ph-survey-rating-button-color);\n+ border-right: 1px solid var(--ph-survey-border-color);\n+ text-align: center;\n+ cursor: pointer;\n+ color: var(--ph-survey-rating-button-text-color);\n+ font-weight: 600;\n+ transition: all 0.2s ease;\n+ font-family: var(--ph-survey-font-family);\n+ }\n+\n+ .ratings-number:last-of-type {\n+ border-right: 0;\n+ }\n+\n+ .ratings-number:hover {\n+ filter: brightness(0.95);\n+ }\n+\n+ .ratings-number.rating-active {\n+ background: var(--ph-survey-rating-active-bg-color);\n+ color: var(--ph-survey-rating-button-active-text-color);\n+ }\n+\n+ /* Button Styling */\n+ .form-submit {\n+ background: var(--ph-survey-submit-button-color);\n+ border: none;\n+ border-radius: var(--ph-survey-border-radius);\n+ padding: 0.875rem 2rem;\n+ font-size: 1rem;\n+ font-weight: 600;\n+ color: var(--ph-survey-submit-button-text-color);\n+ cursor: pointer;\n+ transition: all 0.2s ease;\n+ width: 100%;\n+ margin-top: 1rem;\n+ font-family: var(--ph-survey-font-family);\n+ }\n+\n+ .form-submit:hover:not([disabled]) {\n+ filter: brightness(0.9);\n+ transform: translateY(-1px);\n+ box-shadow: 0 4px 12px rgba(37, 99, 235, 0.3);\n+ }\n+\n+ .form-submit:active:not([disabled]) {\n+ transform: translateY(0);\n+ }\n+\n+ .form-submit[disabled] {\n+ opacity: var(--ph-survey-disabled-button-opacity);\n+ cursor: not-allowed;\n+ }\n+\n+ /* Footer Branding */\n+ .footer-branding {\n+ font-size: 11px;\n+ font-weight: 500;\n+ display: flex;\n+ justify-content: center;\n+ gap: 4px;\n+ align-items: center;\n+ text-decoration: none;\n+ opacity: 0.6;\n+ transition: all 0.2s ease;\n+ color: var(--ph-survey-text-subtle-color);\n+ font-family: var(--ph-survey-font-family);\n+ }\n+\n+ .footer-branding:hover {\n+ opacity: 1;\n+ }\n+\n+ .footer-branding a {\n+ text-decoration: none;\n+ color: inherit;\n+ }\n+\n+ /* Thank You Message */\n+ .thank-you-message {\n+ text-align: center;\n+ padding: 2rem;\n+ }\n+\n+ .thank-you-message-header {\n+ font-size: 1.5rem;\n+ font-weight: 700;\n+ color: var(--ph-survey-text-primary-color);\n+ margin: 0 0 1rem 0;\n+ }\n+\n+ .thank-you-message-body {\n+ font-size: 1rem;\n+ color: var(--ph-survey-text-subtle-color);\n+ opacity: 0.8;\n+ }\n+\n+ /* Scrollbar Styling */\n+ .multiple-choice-options::-webkit-scrollbar {\n+ width: 6px;\n+ }\n+\n+ .multiple-choice-options::-webkit-scrollbar-track {\n+ background: #f1f5f9;\n+ border-radius: 3px;\n+ }\n+\n+ .multiple-choice-options::-webkit-scrollbar-thumb {\n+ background: #cbd5e1;\n+ border-radius: 3px;\n+ }\n+\n+ .multiple-choice-options::-webkit-scrollbar-thumb:hover {\n+ background: #94a3b8;\n+ }\n+\n+ /* Loading State */\n+ .loading {\n+ text-align: center;\n+ padding: 3rem 2rem;\n+ color: var(--ph-survey-text-subtle-color);\n+ display: flex;\n+ flex-direction: column;\n+ align-items: center;\n+ justify-content: center;\n+ flex: 1;\n+ }\n+\n+ .loading-spinner {\n+ display: inline-block;\n+ width: 32px;\n+ height: 32px;\n+ border: 3px solid #e5e7eb;\n+ border-top: 3px solid var(--ph-survey-rating-active-bg-color);\n+ border-radius: 50%;\n+ animation: spin 1s linear infinite;\n+ margin-bottom: 1rem;\n+ }\n+\n+ .loading-text {\n+ font-size: 1.125rem;\n+ font-weight: 500;\n+ }\n+\n+ /* Hide loading when survey is rendered */\n+ #posthog-survey-container:has(.ph-survey) .loading {\n+ display: none;\n+ }\n+\n+ /* Animations */\n+ @keyframes spin {\n+ 0% {\n+ transform: rotate(0deg);\n+ }\n+\n+ 100% {\n+ transform: rotate(360deg);\n+ }\n+ }\n+\n+ @keyframes slideUp {\n+ from {\n+ opacity: 0;\n+ transform: translateY(30px);\n+ }\n+\n+ to {\n+ opacity: 1;\n+ transform: translateY(0);\n+ }\n+ }\n+\n+ /* Responsive Design */\n+ @media (max-width: 768px) {\n+ .main-container {\n+ padding: 0.5rem;\n+ }\n+\n+ .survey-header {\n+ padding: 1.5rem 1.5rem 1.25rem;\n+ }\n+\n+ .survey-title {\n+ font-size: 1.5rem;\n+ }\n+\n+ .survey-description {\n+ font-size: 0.9rem;\n+ }\n+\n+ .survey-form,\n+ .thank-you-message {\n+ padding: 1.25rem 1.5rem;\n+ }\n+\n+ .multiple-choice-options {\n+ max-height: 256px;\n+ }\n+ }\n+\n+ @media (max-height: 700px) {\n+ .main-container {\n+ padding: 0.75rem;\n+ }\n+\n+ .survey-header {\n+ padding: 1.25rem 2rem 1rem;\n+ }\n+\n+ .survey-title {\n+ font-size: 1.5rem;\n+ margin-bottom: 0.25rem;\n+ }\n+\n+ .survey-description {\n+ font-size: 0.9rem;\n+ }\n+\n+ .survey-form,\n+ .thank-you-message {\n+ padding: 1.25rem 2rem;\n+ }\n+ }\n+\n+ /* Utility classes */\n+ .sr-only {\n+ position: absolute;\n+ width: 1px;\n+ height: 1px;\n+ padding: 0;\n+ margin: -1px;\n+ overflow: hidden;\n+ clip: rect(0, 0, 0, 0);\n+ white-space: nowrap;\n+ border: 0;\n+ }\n+\n+ /* Motion preferences */\n+ @media (prefers-reduced-motion: reduce) {\n+ * {\n+ animation-duration: 0.01ms !important;\n+ animation-iteration-count: 1 !important;\n+ transition-duration: 0.01ms !important;\n+ }\n+ }\n+ </style>\n+</head>\n+\n+<body>\n+ <div class=\"main-container\">\n+ <div class=\"survey-card\">\n+ <div class=\"survey-header\">\n+ <h1 class=\"survey-title\">{{ name }}</h1>\n+ </div>\n+\n+ <div class=\"survey-content\">\n+ <div id=\"posthog-survey-container\">\n+ <div class=\"loading\">\n+ <div class=\"loading-spinner\"></div>\n+ <div class=\"loading-text\">Loading survey...</div>\n+ </div>\n+ </div>\n+ </div>\n+ </div>\n+ </div>\n+\n+ <!-- PostHog JavaScript -->\n+ <script>\n+ // Project configuration from Django context\n+ window.projectConfig = {{ project_config_json | safe }};\n+ window.surveyName = \"{{ name }}\";\n+ window.surveyId = \"{{ id }}\";\n+ window.surveyAppearance = {{ appearance | safe }};\n+\n+ const BLACK_TEXT_COLOR = '#020617'\n+\n+ function hex2rgb(c) {\n+ if (c[0] === '#') {\n+ const hexColor = c.replace(/^#/, '')\n+ const r = parseInt(hexColor.slice(0, 2), 16)\n+ const g = parseInt(hexColor.slice(2, 4), 16)\n+ const b = parseInt(hexColor.slice(4, 6), 16)\n+ return 'rgb(' + r + ',' + g + ',' + b + ')'\n+ }\n+ return 'rgb(255, 255, 255)'\n+ }\n+\n+\n+ function nameToHex(name) {\n+ return {\n+ aliceblue: '#f0f8ff',\n+ antiquewhite: '#faebd7',\n+ aqua: '#00ffff',\n+ aquamarine: '#7fffd4',\n+ azure: '#f0ffff',\n+ beige: '#f5f5dc',\n+ bisque: '#ffe4c4',\n+ black: '#000000',\n+ blanchedalmond: '#ffebcd',\n+ blue: '#0000ff',\n+ blueviolet: '#8a2be2',\n+ brown: '#a52a2a',\n+ burlywood: '#deb887',\n+ cadetblue: '#5f9ea0',\n+ chartreuse: '#7fff00',\n+ chocolate: '#d2691e',\n+ coral: '#ff7f50',\n+ cornflowerblue: '#6495ed',\n+ cornsilk: '#fff8dc',\n+ crimson: '#dc143c',\n+ cyan: '#00ffff',\n+ darkblue: '#00008b',\n+ darkcyan: '#008b8b',\n+ darkgoldenrod: '#b8860b',\n+ darkgray: '#a9a9a9',\n+ darkgreen: '#006400',\n+ darkkhaki: '#bdb76b',\n+ darkmagenta: '#8b008b',\n+ darkolivegreen: '#556b2f',\n+ darkorange: '#ff8c00',\n+ darkorchid: '#9932cc',\n+ darkred: '#8b0000',\n+ darksalmon: '#e9967a',\n+ darkseagreen: '#8fbc8f',\n+ darkslateblue: '#483d8b',\n+ darkslategray: '#2f4f4f',\n+ darkturquoise: '#00ced1',\n+ darkviolet: '#9400d3',\n+ deeppink: '#ff1493',\n+ deepskyblue: '#00bfff',\n+ dimgray: '#696969',\n+ dodgerblue: '#1e90ff',\n+ firebrick: '#b22222',\n+ floralwhite: '#fffaf0',\n+ forestgreen: '#228b22',\n+ fuchsia: '#ff00ff',\n+ gainsboro: '#dcdcdc',\n+ ghostwhite: '#f8f8ff',\n+ gold: '#ffd700',\n+ goldenrod: '#daa520',\n+ gray: '#808080',\n+ green: '#008000',\n+ greenyellow: '#adff2f',\n+ honeydew: '#f0fff0',\n+ hotpink: '#ff69b4',\n+ 'indianred ': '#cd5c5c',\n+ indigo: '#4b0082',\n+ ivory: '#fffff0',\n+ khaki: '#f0e68c',\n+ lavender: '#e6e6fa',\n+ lavenderblush: '#fff0f5',\n+ lawngreen: '#7cfc00',\n+ lemonchiffon: '#fffacd',\n+ lightblue: '#add8e6',\n+ lightcoral: '#f08080',\n+ lightcyan: '#e0ffff',\n+ lightgoldenrodyellow: '#fafad2',\n+ lightgrey: '#d3d3d3',\n+ lightgreen: '#90ee90',\n+ lightpink: '#ffb6c1',\n+ lightsalmon: '#ffa07a',\n+ lightseagreen: '#20b2aa',\n+ lightskyblue: '#87cefa',\n+ lightslategray: '#778899',\n+ lightsteelblue: '#b0c4de',\n+ lightyellow: '#ffffe0',\n+ lime: '#00ff00',\n+ limegreen: '#32cd32',\n+ linen: '#faf0e6',\n+ magenta: '#ff00ff',\n+ maroon: '#800000',\n+ mediumaquamarine: '#66cdaa',\n+ mediumblue: '#0000cd',\n+ mediumorchid: '#ba55d3',\n+ mediumpurple: '#9370d8',\n+ mediumseagreen: '#3cb371',\n+ mediumslateblue: '#7b68ee',\n+ mediumspringgreen: '#00fa9a',\n+ mediumturquoise: '#48d1cc',\n+ mediumvioletred: '#c71585',\n+ midnightblue: '#191970',\n+ mintcream: '#f5fffa',\n+ mistyrose: '#ffe4e1',\n+ moccasin: '#ffe4b5',\n+ navajowhite: '#ffdead',\n+ navy: '#000080',\n+ oldlace: '#fdf5e6',\n+ olive: '#808000',\n+ olivedrab: '#6b8e23',\n+ orange: '#ffa500',\n+ orangered: '#ff4500',\n+ orchid: '#da70d6',\n+ palegoldenrod: '#eee8aa',\n+ palegreen: '#98fb98',\n+ paleturquoise: '#afeeee',\n+ palevioletred: '#d87093',\n+ papayawhip: '#ffefd5',\n+ peachpuff: '#ffdab9',\n+ peru: '#cd853f',\n+ pink: '#ffc0cb',\n+ plum: '#dda0dd',\n+ powderblue: '#b0e0e6',\n+ purple: '#800080',\n+ red: '#ff0000',\n+ rosybrown: '#bc8f8f',\n+ royalblue: '#4169e1',\n+ saddlebrown: '#8b4513',\n+ salmon: '#fa8072',\n+ sandybrown: '#f4a460',\n+ seagreen: '#2e8b57',\n+ seashell: '#fff5ee',\n+ sienna: '#a0522d',\n+ silver: '#c0c0c0',\n+ skyblue: '#87ceeb',\n+ slateblue: '#6a5acd',\n+ slategray: '#708090',\n+ snow: '#fffafa',\n+ springgreen: '#00ff7f',\n+ steelblue: '#4682b4',\n+ tan: '#d2b48c',\n+ teal: '#008080',\n+ thistle: '#d8bfd8',\n+ tomato: '#ff6347',\n+ turquoise: '#40e0d0',\n+ violet: '#ee82ee',\n+ wheat: '#f5deb3',\n+ white: '#ffffff',\n+ whitesmoke: '#f5f5f5',\n+ yellow: '#ffff00',\n+ yellowgreen: '#9acd32',\n+ }[name.toLowerCase()]\n+ }\n+\n+ function getContrastingTextColor(color) {\n+ let rgb\n+ if (color[0] === '#') {\n+ rgb = hex2rgb(color)\n+ }\n+ if (color.startsWith('rgb')) {\n+ rgb = color\n+ }\n+ // otherwise it's a color name\n+ const nameColorToHex = nameToHex(color)\n+ if (nameColorToHex) {\n+ rgb = hex2rgb(nameColorToHex)\n+ }\n+ if (!rgb) {\n+ return BLACK_TEXT_COLOR\n+ }\n+ const colorMatch = rgb.match(/^rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)(?:,\\s*(\\d+(?:\\.\\d+)?))?\\)$/)\n+ if (colorMatch) {\n+ const r = parseInt(colorMatch[1])\n+ const g = parseInt(colorMatch[2])\n+ const b = parseInt(colorMatch[3])\n+ const hsp = Math.sqrt(0.299 * (r * r) + 0.587 * (g * g) + 0.114 * (b * b))\n+ return hsp > 127.5 ? BLACK_TEXT_COLOR : 'white'\n+ }\n+ return BLACK_TEXT_COLOR\n+ }\n+\n+ function colorToRgbaWithOpacity(color, opacity = 0.25) {\n+ let rgb\n+\n+ // Handle hex colors\n+ if (color[0] === '#') {\n+ rgb = hex2rgb(color)\n+ }\n+ // Handle rgb/rgba colors\n+ else if (color.startsWith('rgb')) {\n+ rgb = color\n+ }\n+ // Handle color names\n+ else {\n+ const nameColorToHex = nameToHex(color)\n+ if (nameColorToHex) {\n+ rgb = hex2rgb(nameColorToHex)\n+ }\n+ }\n+\n+ if (!rgb) {\n+ return `rgba(255, 255, 255, ${opacity})` // fallback to white with opacity\n+ }\n+\n+ const colorMatch = rgb.match(/^rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)(?:,\\s*(\\d+(?:\\.\\d+)?))?\\)$/)\n+ if (colorMatch) {\n+ const r = parseInt(colorMatch[1])\n+ const g = parseInt(colorMatch[2])\n+ const b = parseInt(colorMatch[3])\n+ return `rgba(${r}, ${g}, ${b}, ${opacity})`\n+ }\n+\n+ return `rgba(255, 255, 255, ${opacity})` // fallback\n+ }\n+\n+\n+ // Apply survey appearance settings as CSS variables\n+ function applySurveyAppearance(appearance) {\n+ if (!appearance) return;\n+\n+ const root = document.documentElement;\n+\n+ // Apply custom appearance settings\n+ if (appearance.backgroundColor) {\n+ // Apply to body and header instead of survey container\n+ // Use 25% opacity for body background for a softer effect\n+ root.style.setProperty('--ph-survey-body-background', colorToRgbaWithOpacity(appearance.backgroundColor, 0.25));\n+ root.style.setProperty('--ph-survey-header-background', appearance.backgroundColor);\n+ root.style.setProperty('--ph-survey-header-text-color', getContrastingTextColor(appearance.backgroundColor));\n+ }\n+\n+ if (appearance.submitButtonColor) {\n+ root.style.setProperty('--ph-survey-submit-button-color', appearance.submitButtonColor);\n+ root.style.setProperty('--ph-survey-submit-button-text-color',\n+ appearance.submitButtonTextColor || getContrastingTextColor(appearance.submitButtonColor));\n+ }\n+\n+ if (appearance.ratingButtonColor) {\n+ root.style.setProperty('--ph-survey-rating-button-color', appearance.ratingButtonColor);\n+ root.style.setProperty('--ph-survey-rating-button-text-color', getContrastingTextColor(appearance.ratingButtonColor));\n+ }\n+\n+ if (appearance.ratingButtonActiveColor) {\n+ root.style.setProperty('--ph-survey-rating-active-bg-color', appearance.ratingButtonActiveColor);\n+ root.style.setProperty('--ph-survey-rating-button-active-text-color', getContrastingTextColor(appearance.ratingButtonActiveColor));\n+ }\n+\n+ if (appearance.borderColor) {\n+ root.style.setProperty('--ph-survey-border-color', appearance.borderColor);\n+ }\n+\n+ if (appearance.borderRadius) {\n+ root.style.setProperty('--ph-survey-border-radius', appearance.borderRadius);\n+ root.style.setProperty('--ph-survey-card-border-radius', appearance.borderRadius);\n+ }\n+\n+ if (appearance.inputBackground) {\n+ root.style.setProperty('--ph-survey-input-background', appearance.inputBackground);\n+ }\n+\n+ if (appearance.textSubtleColor) {\n+ root.style.setProperty('--ph-survey-text-subtle-color', appearance.textSubtleColor);\n+ }\n+\n+ if (appearance.disabledButtonOpacity) {\n+ root.style.setProperty('--ph-survey-disabled-button-opacity', appearance.disabledButtonOpacity);\n+ }\n+\n+ // Properties not suitable for external surveys (ignored):\n+ // - zIndex: not relevant for full page\n+ // - maxWidth: we manage our own layout\n+ // - position: not relevant for full page\n+ // - boxShadow: we have our own design\n+ // - boxPadding: we have our own padding\n+ // - fontFamily: we have our own font stack\n+ // - whiteLabel: not relevant for this context\n+ // - placeholder: handled by PostHog survey rendering\n+ // - shuffleQuestions: behavioral setting, not appearance\n+ // - thankYouMessageHeader/thankYouMessageDescription: handled by PostHog survey rendering\n+ // - displayThankYouMessage: handled by PostHog survey rendering\n+ }\n+\n+ // Apply survey appearance if available\n+ if (window.surveyAppearance) {\n+ applySurveyAppearance(window.surveyAppearance);\n+ }\n+\n+ // Load PostHog from CDN",
|
|
"repo_full_name": "PostHog/posthog",
|
|
"discussion_comments": [
|
|
{
|
|
"comment_id": "2204234815",
|
|
"repo_full_name": "PostHog/posthog",
|
|
"pr_number": 33948,
|
|
"pr_file": "posthog/templates/surveys/public_survey.html",
|
|
"discussion_id": "2204234815",
|
|
"commented_code": "@@ -0,0 +1,935 @@\n+<!DOCTYPE html>\n+<html lang=\"en\">\n+\n+<head>\n+ <meta charset=\"UTF-8\">\n+ <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n+ <title>{{ name }}</title>\n+ <meta name=\"description\" content=\"Take our survey: {{ name }}\">\n+ <style>\n+ /* CSS Variables */\n+ :root {\n+ --ph-survey-font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', Helvetica, Arial, sans-serif;\n+ --ph-survey-border-color: #e5e7eb;\n+ --ph-survey-border-radius: 8px;\n+ --ph-survey-card-border-radius: 16px;\n+ --ph-survey-body-background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n+ --ph-survey-header-background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n+ --ph-survey-header-text-color: white;\n+ --ph-survey-background-color: #ffffff;\n+ --ph-survey-text-primary-color: #111827;\n+ --ph-survey-text-subtle-color: #6b7280;\n+ --ph-survey-input-background: #ffffff;\n+ --ph-survey-submit-button-color: #2563eb;\n+ --ph-survey-submit-button-text-color: white;\n+ --ph-survey-rating-button-color: #f8fafc;\n+ --ph-survey-rating-active-bg-color: #2563eb;\n+ --ph-survey-rating-button-text-color: #374151;\n+ --ph-survey-rating-button-active-text-color: white;\n+ --ph-survey-disabled-button-opacity: 0.6;\n+ --ph-survey-focus-ring: 0 0 0 3px rgba(37, 99, 235, 0.1);\n+ --ph-survey-box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);\n+ }\n+\n+ * {\n+ box-sizing: border-box;\n+ }\n+\n+ /* Base Layout */\n+ body {\n+ font-family: var(--ph-survey-font-family);\n+ margin: 0;\n+ padding: 0;\n+ background: var(--ph-survey-body-background);\n+ min-height: 100vh;\n+ line-height: 1.6;\n+ color: var(--ph-survey-text-primary-color);\n+ font-size: 16px;\n+ -webkit-font-smoothing: antialiased;\n+ }\n+\n+ .main-container {\n+ min-height: 100vh;\n+ display: flex;\n+ align-items: center;\n+ justify-content: center;\n+ padding: 1rem;\n+ box-sizing: border-box;\n+ }\n+\n+ .survey-card {\n+ background: white;\n+ border-radius: var(--ph-survey-card-border-radius);\n+ box-shadow: var(--ph-survey-box-shadow);\n+ max-width: 720px;\n+ width: 100%;\n+ overflow: hidden;\n+ max-height: 90vh;\n+ display: flex;\n+ flex-direction: column;\n+ animation: slideUp 0.6s ease-out;\n+ }\n+\n+ /* Survey Header */\n+ .survey-header {\n+ background: var(--ph-survey-header-background);\n+ color: var(--ph-survey-header-text-color);\n+ padding: 1.75rem 2rem 1.5rem;\n+ text-align: center;\n+ flex-shrink: 0;\n+ }\n+\n+ .survey-title {\n+ font-size: 1.75rem;\n+ font-weight: 700;\n+ margin: 0;\n+ }\n+\n+ .survey-description {\n+ font-size: 1rem;\n+ margin: 0;\n+ opacity: 0.9;\n+ line-height: 1.4;\n+ }\n+\n+ /* Survey Content */\n+ .survey-content {\n+ flex: 1;\n+ display: flex;\n+ flex-direction: column;\n+ min-height: 0;\n+ }\n+\n+ .survey-box {\n+ display: flex;\n+ flex-direction: column;\n+ gap: 1rem;\n+ flex: 1;\n+ min-height: 0;\n+ }\n+\n+ .bottom-section {\n+ display: flex;\n+ flex-direction: column;\n+ gap: 0.75rem;\n+ }\n+\n+ .survey-form,\n+ .thank-you-message {\n+ width: 100%;\n+ margin: 0;\n+ border: none;\n+ border-radius: 0;\n+ box-shadow: none;\n+ background: white;\n+ padding: 1.5rem 2rem;\n+ display: flex;\n+ flex-direction: column;\n+ justify-content: center;\n+ min-height: 0;\n+ }\n+\n+ /* Question Styling */\n+ .survey-question {\n+ font-size: 1.25rem;\n+ font-weight: 600;\n+ color: var(--ph-survey-text-primary-color);\n+ line-height: 1.4;\n+ margin: 0;\n+ }\n+\n+ .survey-question-description {\n+ font-size: 1rem;\n+ color: var(--ph-survey-text-subtle-color);\n+ margin-top: 0.25rem;\n+ margin-bottom: 1.25rem;\n+ }\n+\n+ .question-container,\n+ .thank-you-message {\n+ display: flex;\n+ flex-direction: column;\n+ justify-content: center;\n+ gap: 8px;\n+ }\n+\n+ .response-choice {\n+ display: flex;\n+ gap: 8px;\n+ align-items: center;\n+ }\n+\n+\n+ /* Input Styling */\n+ textarea,\n+ input[type='text'] {\n+ border: 2px solid var(--ph-survey-border-color);\n+ border-radius: var(--ph-survey-border-radius);\n+ padding: 1rem;\n+ font-size: 1rem;\n+ line-height: 1.5;\n+ transition: all 0.2s ease;\n+ background: var(--ph-survey-input-background);\n+ color: var(--ph-survey-text-primary-color);\n+ width: 100%;\n+ font-family: var(--ph-survey-font-family);\n+ }\n+\n+ textarea:focus,\n+ input[type='text']:focus {\n+ outline: none;\n+ border-color: var(--ph-survey-rating-active-bg-color);\n+ box-shadow: var(--ph-survey-focus-ring);\n+ }\n+\n+ textarea:hover:not(:focus),\n+ input[type='text']:hover:not(:focus) {\n+ border-color: var(--ph-survey-rating-active-bg-color);\n+ }\n+\n+ /* Multiple Choice Options */\n+ .multiple-choice-options {\n+ display: flex;\n+ flex-direction: column;\n+ gap: 0.625rem;\n+ flex: 1;\n+ justify-content: flex-start;\n+ overflow-y: auto;\n+ max-height: 400px;\n+ padding-right: 0.5rem;\n+ margin: 0;\n+ padding-left: 0;\n+ border: none;\n+ }\n+\n+ /* Fieldset styling */\n+ fieldset {\n+ border: none;\n+ margin: 0;\n+ padding: 0;\n+ }\n+\n+ .multiple-choice-options label {\n+ border: 2px solid var(--ph-survey-border-color);\n+ border-radius: var(--ph-survey-border-radius);\n+ padding: 0.875rem 1.25rem;\n+ cursor: pointer;\n+ transition: all 0.2s ease;\n+ background: white;\n+ font-size: 1rem;\n+ min-height: 56px;\n+ display: flex;\n+ align-items: center;\n+ gap: 12px;\n+ flex-shrink: 0;\n+ color: var(--ph-survey-text-primary-color);\n+ font-family: var(--ph-survey-font-family);\n+ }\n+\n+ .choice-option-open {\n+ flex-wrap: wrap;\n+ }\n+\n+ .multiple-choice-options label:hover:not(:has(input:checked)) {\n+ border-color: #d1d5db;\n+ background: #f9fafb;\n+ }\n+\n+ .multiple-choice-options label:has(input:checked) {\n+ border-color: var(--ph-survey-rating-active-bg-color);\n+ background: #eff6ff;\n+ }\n+\n+ .multiple-choice-options input[type='checkbox'],\n+ .multiple-choice-options input[type='radio'] {\n+ appearance: none;\n+ width: 1rem;\n+ height: 1rem;\n+ background: var(--ph-survey-input-background);\n+ border: 1.5px solid var(--ph-survey-border-color);\n+ cursor: pointer;\n+ border-radius: 3px;\n+ flex-shrink: 0;\n+ transition: all 0.2s ease;\n+ position: relative;\n+ margin: 0;\n+ }\n+\n+ .multiple-choice-options input[type='radio'] {\n+ border-radius: 50%;\n+ }\n+\n+ .multiple-choice-options input[type='checkbox']:hover,\n+ .multiple-choice-options input[type='radio']:hover {\n+ border-color: var(--ph-survey-rating-active-bg-color);\n+ transform: scale(1.05);\n+ }\n+\n+ .multiple-choice-options input[type='checkbox']:checked,\n+ .multiple-choice-options input[type='radio']:checked {\n+ background: var(--ph-survey-rating-active-bg-color);\n+ border-color: var(--ph-survey-rating-active-bg-color);\n+ }\n+\n+ .multiple-choice-options input[type='checkbox']:checked::after {\n+ content: '';\n+ position: absolute;\n+ left: 4px;\n+ width: 4px;\n+ height: 8px;\n+ border: solid white;\n+ border-width: 0 2px 2px 0;\n+ transform: rotate(45deg);\n+ }\n+\n+ .multiple-choice-options input[type='radio']:checked::after {\n+ content: '';\n+ position: absolute;\n+ left: 3.5px;\n+ top: 3.5px;\n+ width: 6px;\n+ height: 6px;\n+ border-radius: 50%;\n+ background: white;\n+ }\n+\n+ /* Rating Styles */\n+ .rating-text {\n+ display: flex;\n+ flex-direction: row;\n+ font-size: 0.8rem;\n+ justify-content: space-between;\n+ opacity: 0.7;\n+ }\n+\n+ .rating-options-number {\n+ display: grid;\n+ grid-auto-columns: 1fr;\n+ grid-auto-flow: column;\n+ border-radius: var(--ph-survey-border-radius);\n+ overflow: hidden;\n+ border: 2px solid var(--ph-survey-border-color);\n+ }\n+\n+ .ratings-number {\n+ padding: 0.875rem 0;\n+ border: none;\n+ background-color: var(--ph-survey-rating-button-color);\n+ border-right: 1px solid var(--ph-survey-border-color);\n+ text-align: center;\n+ cursor: pointer;\n+ color: var(--ph-survey-rating-button-text-color);\n+ font-weight: 600;\n+ transition: all 0.2s ease;\n+ font-family: var(--ph-survey-font-family);\n+ }\n+\n+ .ratings-number:last-of-type {\n+ border-right: 0;\n+ }\n+\n+ .ratings-number:hover {\n+ filter: brightness(0.95);\n+ }\n+\n+ .ratings-number.rating-active {\n+ background: var(--ph-survey-rating-active-bg-color);\n+ color: var(--ph-survey-rating-button-active-text-color);\n+ }\n+\n+ /* Button Styling */\n+ .form-submit {\n+ background: var(--ph-survey-submit-button-color);\n+ border: none;\n+ border-radius: var(--ph-survey-border-radius);\n+ padding: 0.875rem 2rem;\n+ font-size: 1rem;\n+ font-weight: 600;\n+ color: var(--ph-survey-submit-button-text-color);\n+ cursor: pointer;\n+ transition: all 0.2s ease;\n+ width: 100%;\n+ margin-top: 1rem;\n+ font-family: var(--ph-survey-font-family);\n+ }\n+\n+ .form-submit:hover:not([disabled]) {\n+ filter: brightness(0.9);\n+ transform: translateY(-1px);\n+ box-shadow: 0 4px 12px rgba(37, 99, 235, 0.3);\n+ }\n+\n+ .form-submit:active:not([disabled]) {\n+ transform: translateY(0);\n+ }\n+\n+ .form-submit[disabled] {\n+ opacity: var(--ph-survey-disabled-button-opacity);\n+ cursor: not-allowed;\n+ }\n+\n+ /* Footer Branding */\n+ .footer-branding {\n+ font-size: 11px;\n+ font-weight: 500;\n+ display: flex;\n+ justify-content: center;\n+ gap: 4px;\n+ align-items: center;\n+ text-decoration: none;\n+ opacity: 0.6;\n+ transition: all 0.2s ease;\n+ color: var(--ph-survey-text-subtle-color);\n+ font-family: var(--ph-survey-font-family);\n+ }\n+\n+ .footer-branding:hover {\n+ opacity: 1;\n+ }\n+\n+ .footer-branding a {\n+ text-decoration: none;\n+ color: inherit;\n+ }\n+\n+ /* Thank You Message */\n+ .thank-you-message {\n+ text-align: center;\n+ padding: 2rem;\n+ }\n+\n+ .thank-you-message-header {\n+ font-size: 1.5rem;\n+ font-weight: 700;\n+ color: var(--ph-survey-text-primary-color);\n+ margin: 0 0 1rem 0;\n+ }\n+\n+ .thank-you-message-body {\n+ font-size: 1rem;\n+ color: var(--ph-survey-text-subtle-color);\n+ opacity: 0.8;\n+ }\n+\n+ /* Scrollbar Styling */\n+ .multiple-choice-options::-webkit-scrollbar {\n+ width: 6px;\n+ }\n+\n+ .multiple-choice-options::-webkit-scrollbar-track {\n+ background: #f1f5f9;\n+ border-radius: 3px;\n+ }\n+\n+ .multiple-choice-options::-webkit-scrollbar-thumb {\n+ background: #cbd5e1;\n+ border-radius: 3px;\n+ }\n+\n+ .multiple-choice-options::-webkit-scrollbar-thumb:hover {\n+ background: #94a3b8;\n+ }\n+\n+ /* Loading State */\n+ .loading {\n+ text-align: center;\n+ padding: 3rem 2rem;\n+ color: var(--ph-survey-text-subtle-color);\n+ display: flex;\n+ flex-direction: column;\n+ align-items: center;\n+ justify-content: center;\n+ flex: 1;\n+ }\n+\n+ .loading-spinner {\n+ display: inline-block;\n+ width: 32px;\n+ height: 32px;\n+ border: 3px solid #e5e7eb;\n+ border-top: 3px solid var(--ph-survey-rating-active-bg-color);\n+ border-radius: 50%;\n+ animation: spin 1s linear infinite;\n+ margin-bottom: 1rem;\n+ }\n+\n+ .loading-text {\n+ font-size: 1.125rem;\n+ font-weight: 500;\n+ }\n+\n+ /* Hide loading when survey is rendered */\n+ #posthog-survey-container:has(.ph-survey) .loading {\n+ display: none;\n+ }\n+\n+ /* Animations */\n+ @keyframes spin {\n+ 0% {\n+ transform: rotate(0deg);\n+ }\n+\n+ 100% {\n+ transform: rotate(360deg);\n+ }\n+ }\n+\n+ @keyframes slideUp {\n+ from {\n+ opacity: 0;\n+ transform: translateY(30px);\n+ }\n+\n+ to {\n+ opacity: 1;\n+ transform: translateY(0);\n+ }\n+ }\n+\n+ /* Responsive Design */\n+ @media (max-width: 768px) {\n+ .main-container {\n+ padding: 0.5rem;\n+ }\n+\n+ .survey-header {\n+ padding: 1.5rem 1.5rem 1.25rem;\n+ }\n+\n+ .survey-title {\n+ font-size: 1.5rem;\n+ }\n+\n+ .survey-description {\n+ font-size: 0.9rem;\n+ }\n+\n+ .survey-form,\n+ .thank-you-message {\n+ padding: 1.25rem 1.5rem;\n+ }\n+\n+ .multiple-choice-options {\n+ max-height: 256px;\n+ }\n+ }\n+\n+ @media (max-height: 700px) {\n+ .main-container {\n+ padding: 0.75rem;\n+ }\n+\n+ .survey-header {\n+ padding: 1.25rem 2rem 1rem;\n+ }\n+\n+ .survey-title {\n+ font-size: 1.5rem;\n+ margin-bottom: 0.25rem;\n+ }\n+\n+ .survey-description {\n+ font-size: 0.9rem;\n+ }\n+\n+ .survey-form,\n+ .thank-you-message {\n+ padding: 1.25rem 2rem;\n+ }\n+ }\n+\n+ /* Utility classes */\n+ .sr-only {\n+ position: absolute;\n+ width: 1px;\n+ height: 1px;\n+ padding: 0;\n+ margin: -1px;\n+ overflow: hidden;\n+ clip: rect(0, 0, 0, 0);\n+ white-space: nowrap;\n+ border: 0;\n+ }\n+\n+ /* Motion preferences */\n+ @media (prefers-reduced-motion: reduce) {\n+ * {\n+ animation-duration: 0.01ms !important;\n+ animation-iteration-count: 1 !important;\n+ transition-duration: 0.01ms !important;\n+ }\n+ }\n+ </style>\n+</head>\n+\n+<body>\n+ <div class=\"main-container\">\n+ <div class=\"survey-card\">\n+ <div class=\"survey-header\">\n+ <h1 class=\"survey-title\">{{ name }}</h1>\n+ </div>\n+\n+ <div class=\"survey-content\">\n+ <div id=\"posthog-survey-container\">\n+ <div class=\"loading\">\n+ <div class=\"loading-spinner\"></div>\n+ <div class=\"loading-text\">Loading survey...</div>\n+ </div>\n+ </div>\n+ </div>\n+ </div>\n+ </div>\n+\n+ <!-- PostHog JavaScript -->\n+ <script>\n+ // Project configuration from Django context\n+ window.projectConfig = {{ project_config_json | safe }};\n+ window.surveyName = \"{{ name }}\";\n+ window.surveyId = \"{{ id }}\";\n+ window.surveyAppearance = {{ appearance | safe }};\n+\n+ const BLACK_TEXT_COLOR = '#020617'\n+\n+ function hex2rgb(c) {\n+ if (c[0] === '#') {\n+ const hexColor = c.replace(/^#/, '')\n+ const r = parseInt(hexColor.slice(0, 2), 16)\n+ const g = parseInt(hexColor.slice(2, 4), 16)\n+ const b = parseInt(hexColor.slice(4, 6), 16)\n+ return 'rgb(' + r + ',' + g + ',' + b + ')'\n+ }\n+ return 'rgb(255, 255, 255)'\n+ }\n+\n+\n+ function nameToHex(name) {\n+ return {\n+ aliceblue: '#f0f8ff',\n+ antiquewhite: '#faebd7',\n+ aqua: '#00ffff',\n+ aquamarine: '#7fffd4',\n+ azure: '#f0ffff',\n+ beige: '#f5f5dc',\n+ bisque: '#ffe4c4',\n+ black: '#000000',\n+ blanchedalmond: '#ffebcd',\n+ blue: '#0000ff',\n+ blueviolet: '#8a2be2',\n+ brown: '#a52a2a',\n+ burlywood: '#deb887',\n+ cadetblue: '#5f9ea0',\n+ chartreuse: '#7fff00',\n+ chocolate: '#d2691e',\n+ coral: '#ff7f50',\n+ cornflowerblue: '#6495ed',\n+ cornsilk: '#fff8dc',\n+ crimson: '#dc143c',\n+ cyan: '#00ffff',\n+ darkblue: '#00008b',\n+ darkcyan: '#008b8b',\n+ darkgoldenrod: '#b8860b',\n+ darkgray: '#a9a9a9',\n+ darkgreen: '#006400',\n+ darkkhaki: '#bdb76b',\n+ darkmagenta: '#8b008b',\n+ darkolivegreen: '#556b2f',\n+ darkorange: '#ff8c00',\n+ darkorchid: '#9932cc',\n+ darkred: '#8b0000',\n+ darksalmon: '#e9967a',\n+ darkseagreen: '#8fbc8f',\n+ darkslateblue: '#483d8b',\n+ darkslategray: '#2f4f4f',\n+ darkturquoise: '#00ced1',\n+ darkviolet: '#9400d3',\n+ deeppink: '#ff1493',\n+ deepskyblue: '#00bfff',\n+ dimgray: '#696969',\n+ dodgerblue: '#1e90ff',\n+ firebrick: '#b22222',\n+ floralwhite: '#fffaf0',\n+ forestgreen: '#228b22',\n+ fuchsia: '#ff00ff',\n+ gainsboro: '#dcdcdc',\n+ ghostwhite: '#f8f8ff',\n+ gold: '#ffd700',\n+ goldenrod: '#daa520',\n+ gray: '#808080',\n+ green: '#008000',\n+ greenyellow: '#adff2f',\n+ honeydew: '#f0fff0',\n+ hotpink: '#ff69b4',\n+ 'indianred ': '#cd5c5c',\n+ indigo: '#4b0082',\n+ ivory: '#fffff0',\n+ khaki: '#f0e68c',\n+ lavender: '#e6e6fa',\n+ lavenderblush: '#fff0f5',\n+ lawngreen: '#7cfc00',\n+ lemonchiffon: '#fffacd',\n+ lightblue: '#add8e6',\n+ lightcoral: '#f08080',\n+ lightcyan: '#e0ffff',\n+ lightgoldenrodyellow: '#fafad2',\n+ lightgrey: '#d3d3d3',\n+ lightgreen: '#90ee90',\n+ lightpink: '#ffb6c1',\n+ lightsalmon: '#ffa07a',\n+ lightseagreen: '#20b2aa',\n+ lightskyblue: '#87cefa',\n+ lightslategray: '#778899',\n+ lightsteelblue: '#b0c4de',\n+ lightyellow: '#ffffe0',\n+ lime: '#00ff00',\n+ limegreen: '#32cd32',\n+ linen: '#faf0e6',\n+ magenta: '#ff00ff',\n+ maroon: '#800000',\n+ mediumaquamarine: '#66cdaa',\n+ mediumblue: '#0000cd',\n+ mediumorchid: '#ba55d3',\n+ mediumpurple: '#9370d8',\n+ mediumseagreen: '#3cb371',\n+ mediumslateblue: '#7b68ee',\n+ mediumspringgreen: '#00fa9a',\n+ mediumturquoise: '#48d1cc',\n+ mediumvioletred: '#c71585',\n+ midnightblue: '#191970',\n+ mintcream: '#f5fffa',\n+ mistyrose: '#ffe4e1',\n+ moccasin: '#ffe4b5',\n+ navajowhite: '#ffdead',\n+ navy: '#000080',\n+ oldlace: '#fdf5e6',\n+ olive: '#808000',\n+ olivedrab: '#6b8e23',\n+ orange: '#ffa500',\n+ orangered: '#ff4500',\n+ orchid: '#da70d6',\n+ palegoldenrod: '#eee8aa',\n+ palegreen: '#98fb98',\n+ paleturquoise: '#afeeee',\n+ palevioletred: '#d87093',\n+ papayawhip: '#ffefd5',\n+ peachpuff: '#ffdab9',\n+ peru: '#cd853f',\n+ pink: '#ffc0cb',\n+ plum: '#dda0dd',\n+ powderblue: '#b0e0e6',\n+ purple: '#800080',\n+ red: '#ff0000',\n+ rosybrown: '#bc8f8f',\n+ royalblue: '#4169e1',\n+ saddlebrown: '#8b4513',\n+ salmon: '#fa8072',\n+ sandybrown: '#f4a460',\n+ seagreen: '#2e8b57',\n+ seashell: '#fff5ee',\n+ sienna: '#a0522d',\n+ silver: '#c0c0c0',\n+ skyblue: '#87ceeb',\n+ slateblue: '#6a5acd',\n+ slategray: '#708090',\n+ snow: '#fffafa',\n+ springgreen: '#00ff7f',\n+ steelblue: '#4682b4',\n+ tan: '#d2b48c',\n+ teal: '#008080',\n+ thistle: '#d8bfd8',\n+ tomato: '#ff6347',\n+ turquoise: '#40e0d0',\n+ violet: '#ee82ee',\n+ wheat: '#f5deb3',\n+ white: '#ffffff',\n+ whitesmoke: '#f5f5f5',\n+ yellow: '#ffff00',\n+ yellowgreen: '#9acd32',\n+ }[name.toLowerCase()]\n+ }\n+\n+ function getContrastingTextColor(color) {\n+ let rgb\n+ if (color[0] === '#') {\n+ rgb = hex2rgb(color)\n+ }\n+ if (color.startsWith('rgb')) {\n+ rgb = color\n+ }\n+ // otherwise it's a color name\n+ const nameColorToHex = nameToHex(color)\n+ if (nameColorToHex) {\n+ rgb = hex2rgb(nameColorToHex)\n+ }\n+ if (!rgb) {\n+ return BLACK_TEXT_COLOR\n+ }\n+ const colorMatch = rgb.match(/^rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)(?:,\\s*(\\d+(?:\\.\\d+)?))?\\)$/)\n+ if (colorMatch) {\n+ const r = parseInt(colorMatch[1])\n+ const g = parseInt(colorMatch[2])\n+ const b = parseInt(colorMatch[3])\n+ const hsp = Math.sqrt(0.299 * (r * r) + 0.587 * (g * g) + 0.114 * (b * b))\n+ return hsp > 127.5 ? BLACK_TEXT_COLOR : 'white'\n+ }\n+ return BLACK_TEXT_COLOR\n+ }\n+\n+ function colorToRgbaWithOpacity(color, opacity = 0.25) {\n+ let rgb\n+\n+ // Handle hex colors\n+ if (color[0] === '#') {\n+ rgb = hex2rgb(color)\n+ }\n+ // Handle rgb/rgba colors\n+ else if (color.startsWith('rgb')) {\n+ rgb = color\n+ }\n+ // Handle color names\n+ else {\n+ const nameColorToHex = nameToHex(color)\n+ if (nameColorToHex) {\n+ rgb = hex2rgb(nameColorToHex)\n+ }\n+ }\n+\n+ if (!rgb) {\n+ return `rgba(255, 255, 255, ${opacity})` // fallback to white with opacity\n+ }\n+\n+ const colorMatch = rgb.match(/^rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)(?:,\\s*(\\d+(?:\\.\\d+)?))?\\)$/)\n+ if (colorMatch) {\n+ const r = parseInt(colorMatch[1])\n+ const g = parseInt(colorMatch[2])\n+ const b = parseInt(colorMatch[3])\n+ return `rgba(${r}, ${g}, ${b}, ${opacity})`\n+ }\n+\n+ return `rgba(255, 255, 255, ${opacity})` // fallback\n+ }\n+\n+\n+ // Apply survey appearance settings as CSS variables\n+ function applySurveyAppearance(appearance) {\n+ if (!appearance) return;\n+\n+ const root = document.documentElement;\n+\n+ // Apply custom appearance settings\n+ if (appearance.backgroundColor) {\n+ // Apply to body and header instead of survey container\n+ // Use 25% opacity for body background for a softer effect\n+ root.style.setProperty('--ph-survey-body-background', colorToRgbaWithOpacity(appearance.backgroundColor, 0.25));\n+ root.style.setProperty('--ph-survey-header-background', appearance.backgroundColor);\n+ root.style.setProperty('--ph-survey-header-text-color', getContrastingTextColor(appearance.backgroundColor));\n+ }\n+\n+ if (appearance.submitButtonColor) {\n+ root.style.setProperty('--ph-survey-submit-button-color', appearance.submitButtonColor);\n+ root.style.setProperty('--ph-survey-submit-button-text-color',\n+ appearance.submitButtonTextColor || getContrastingTextColor(appearance.submitButtonColor));\n+ }\n+\n+ if (appearance.ratingButtonColor) {\n+ root.style.setProperty('--ph-survey-rating-button-color', appearance.ratingButtonColor);\n+ root.style.setProperty('--ph-survey-rating-button-text-color', getContrastingTextColor(appearance.ratingButtonColor));\n+ }\n+\n+ if (appearance.ratingButtonActiveColor) {\n+ root.style.setProperty('--ph-survey-rating-active-bg-color', appearance.ratingButtonActiveColor);\n+ root.style.setProperty('--ph-survey-rating-button-active-text-color', getContrastingTextColor(appearance.ratingButtonActiveColor));\n+ }\n+\n+ if (appearance.borderColor) {\n+ root.style.setProperty('--ph-survey-border-color', appearance.borderColor);\n+ }\n+\n+ if (appearance.borderRadius) {\n+ root.style.setProperty('--ph-survey-border-radius', appearance.borderRadius);\n+ root.style.setProperty('--ph-survey-card-border-radius', appearance.borderRadius);\n+ }\n+\n+ if (appearance.inputBackground) {\n+ root.style.setProperty('--ph-survey-input-background', appearance.inputBackground);\n+ }\n+\n+ if (appearance.textSubtleColor) {\n+ root.style.setProperty('--ph-survey-text-subtle-color', appearance.textSubtleColor);\n+ }\n+\n+ if (appearance.disabledButtonOpacity) {\n+ root.style.setProperty('--ph-survey-disabled-button-opacity', appearance.disabledButtonOpacity);\n+ }\n+\n+ // Properties not suitable for external surveys (ignored):\n+ // - zIndex: not relevant for full page\n+ // - maxWidth: we manage our own layout\n+ // - position: not relevant for full page\n+ // - boxShadow: we have our own design\n+ // - boxPadding: we have our own padding\n+ // - fontFamily: we have our own font stack\n+ // - whiteLabel: not relevant for this context\n+ // - placeholder: handled by PostHog survey rendering\n+ // - shuffleQuestions: behavioral setting, not appearance\n+ // - thankYouMessageHeader/thankYouMessageDescription: handled by PostHog survey rendering\n+ // - displayThankYouMessage: handled by PostHog survey rendering\n+ }\n+\n+ // Apply survey appearance if available\n+ if (window.surveyAppearance) {\n+ applySurveyAppearance(window.surveyAppearance);\n+ }\n+\n+ // Load PostHog from CDN",
|
|
"comment_created_at": "2025-07-14T08:41:06+00:00",
|
|
"comment_author": "marandaneto",
|
|
"comment_body": "the posthog js SDK should be already installed/inited in the posthog app, can we reuse the JS SDK/its instance instead for all of that?",
|
|
"pr_file_module": null
|
|
},
|
|
{
|
|
"comment_id": "2206144161",
|
|
"repo_full_name": "PostHog/posthog",
|
|
"pr_number": 33948,
|
|
"pr_file": "posthog/templates/surveys/public_survey.html",
|
|
"discussion_id": "2204234815",
|
|
"commented_code": "@@ -0,0 +1,935 @@\n+<!DOCTYPE html>\n+<html lang=\"en\">\n+\n+<head>\n+ <meta charset=\"UTF-8\">\n+ <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n+ <title>{{ name }}</title>\n+ <meta name=\"description\" content=\"Take our survey: {{ name }}\">\n+ <style>\n+ /* CSS Variables */\n+ :root {\n+ --ph-survey-font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', Helvetica, Arial, sans-serif;\n+ --ph-survey-border-color: #e5e7eb;\n+ --ph-survey-border-radius: 8px;\n+ --ph-survey-card-border-radius: 16px;\n+ --ph-survey-body-background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n+ --ph-survey-header-background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n+ --ph-survey-header-text-color: white;\n+ --ph-survey-background-color: #ffffff;\n+ --ph-survey-text-primary-color: #111827;\n+ --ph-survey-text-subtle-color: #6b7280;\n+ --ph-survey-input-background: #ffffff;\n+ --ph-survey-submit-button-color: #2563eb;\n+ --ph-survey-submit-button-text-color: white;\n+ --ph-survey-rating-button-color: #f8fafc;\n+ --ph-survey-rating-active-bg-color: #2563eb;\n+ --ph-survey-rating-button-text-color: #374151;\n+ --ph-survey-rating-button-active-text-color: white;\n+ --ph-survey-disabled-button-opacity: 0.6;\n+ --ph-survey-focus-ring: 0 0 0 3px rgba(37, 99, 235, 0.1);\n+ --ph-survey-box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);\n+ }\n+\n+ * {\n+ box-sizing: border-box;\n+ }\n+\n+ /* Base Layout */\n+ body {\n+ font-family: var(--ph-survey-font-family);\n+ margin: 0;\n+ padding: 0;\n+ background: var(--ph-survey-body-background);\n+ min-height: 100vh;\n+ line-height: 1.6;\n+ color: var(--ph-survey-text-primary-color);\n+ font-size: 16px;\n+ -webkit-font-smoothing: antialiased;\n+ }\n+\n+ .main-container {\n+ min-height: 100vh;\n+ display: flex;\n+ align-items: center;\n+ justify-content: center;\n+ padding: 1rem;\n+ box-sizing: border-box;\n+ }\n+\n+ .survey-card {\n+ background: white;\n+ border-radius: var(--ph-survey-card-border-radius);\n+ box-shadow: var(--ph-survey-box-shadow);\n+ max-width: 720px;\n+ width: 100%;\n+ overflow: hidden;\n+ max-height: 90vh;\n+ display: flex;\n+ flex-direction: column;\n+ animation: slideUp 0.6s ease-out;\n+ }\n+\n+ /* Survey Header */\n+ .survey-header {\n+ background: var(--ph-survey-header-background);\n+ color: var(--ph-survey-header-text-color);\n+ padding: 1.75rem 2rem 1.5rem;\n+ text-align: center;\n+ flex-shrink: 0;\n+ }\n+\n+ .survey-title {\n+ font-size: 1.75rem;\n+ font-weight: 700;\n+ margin: 0;\n+ }\n+\n+ .survey-description {\n+ font-size: 1rem;\n+ margin: 0;\n+ opacity: 0.9;\n+ line-height: 1.4;\n+ }\n+\n+ /* Survey Content */\n+ .survey-content {\n+ flex: 1;\n+ display: flex;\n+ flex-direction: column;\n+ min-height: 0;\n+ }\n+\n+ .survey-box {\n+ display: flex;\n+ flex-direction: column;\n+ gap: 1rem;\n+ flex: 1;\n+ min-height: 0;\n+ }\n+\n+ .bottom-section {\n+ display: flex;\n+ flex-direction: column;\n+ gap: 0.75rem;\n+ }\n+\n+ .survey-form,\n+ .thank-you-message {\n+ width: 100%;\n+ margin: 0;\n+ border: none;\n+ border-radius: 0;\n+ box-shadow: none;\n+ background: white;\n+ padding: 1.5rem 2rem;\n+ display: flex;\n+ flex-direction: column;\n+ justify-content: center;\n+ min-height: 0;\n+ }\n+\n+ /* Question Styling */\n+ .survey-question {\n+ font-size: 1.25rem;\n+ font-weight: 600;\n+ color: var(--ph-survey-text-primary-color);\n+ line-height: 1.4;\n+ margin: 0;\n+ }\n+\n+ .survey-question-description {\n+ font-size: 1rem;\n+ color: var(--ph-survey-text-subtle-color);\n+ margin-top: 0.25rem;\n+ margin-bottom: 1.25rem;\n+ }\n+\n+ .question-container,\n+ .thank-you-message {\n+ display: flex;\n+ flex-direction: column;\n+ justify-content: center;\n+ gap: 8px;\n+ }\n+\n+ .response-choice {\n+ display: flex;\n+ gap: 8px;\n+ align-items: center;\n+ }\n+\n+\n+ /* Input Styling */\n+ textarea,\n+ input[type='text'] {\n+ border: 2px solid var(--ph-survey-border-color);\n+ border-radius: var(--ph-survey-border-radius);\n+ padding: 1rem;\n+ font-size: 1rem;\n+ line-height: 1.5;\n+ transition: all 0.2s ease;\n+ background: var(--ph-survey-input-background);\n+ color: var(--ph-survey-text-primary-color);\n+ width: 100%;\n+ font-family: var(--ph-survey-font-family);\n+ }\n+\n+ textarea:focus,\n+ input[type='text']:focus {\n+ outline: none;\n+ border-color: var(--ph-survey-rating-active-bg-color);\n+ box-shadow: var(--ph-survey-focus-ring);\n+ }\n+\n+ textarea:hover:not(:focus),\n+ input[type='text']:hover:not(:focus) {\n+ border-color: var(--ph-survey-rating-active-bg-color);\n+ }\n+\n+ /* Multiple Choice Options */\n+ .multiple-choice-options {\n+ display: flex;\n+ flex-direction: column;\n+ gap: 0.625rem;\n+ flex: 1;\n+ justify-content: flex-start;\n+ overflow-y: auto;\n+ max-height: 400px;\n+ padding-right: 0.5rem;\n+ margin: 0;\n+ padding-left: 0;\n+ border: none;\n+ }\n+\n+ /* Fieldset styling */\n+ fieldset {\n+ border: none;\n+ margin: 0;\n+ padding: 0;\n+ }\n+\n+ .multiple-choice-options label {\n+ border: 2px solid var(--ph-survey-border-color);\n+ border-radius: var(--ph-survey-border-radius);\n+ padding: 0.875rem 1.25rem;\n+ cursor: pointer;\n+ transition: all 0.2s ease;\n+ background: white;\n+ font-size: 1rem;\n+ min-height: 56px;\n+ display: flex;\n+ align-items: center;\n+ gap: 12px;\n+ flex-shrink: 0;\n+ color: var(--ph-survey-text-primary-color);\n+ font-family: var(--ph-survey-font-family);\n+ }\n+\n+ .choice-option-open {\n+ flex-wrap: wrap;\n+ }\n+\n+ .multiple-choice-options label:hover:not(:has(input:checked)) {\n+ border-color: #d1d5db;\n+ background: #f9fafb;\n+ }\n+\n+ .multiple-choice-options label:has(input:checked) {\n+ border-color: var(--ph-survey-rating-active-bg-color);\n+ background: #eff6ff;\n+ }\n+\n+ .multiple-choice-options input[type='checkbox'],\n+ .multiple-choice-options input[type='radio'] {\n+ appearance: none;\n+ width: 1rem;\n+ height: 1rem;\n+ background: var(--ph-survey-input-background);\n+ border: 1.5px solid var(--ph-survey-border-color);\n+ cursor: pointer;\n+ border-radius: 3px;\n+ flex-shrink: 0;\n+ transition: all 0.2s ease;\n+ position: relative;\n+ margin: 0;\n+ }\n+\n+ .multiple-choice-options input[type='radio'] {\n+ border-radius: 50%;\n+ }\n+\n+ .multiple-choice-options input[type='checkbox']:hover,\n+ .multiple-choice-options input[type='radio']:hover {\n+ border-color: var(--ph-survey-rating-active-bg-color);\n+ transform: scale(1.05);\n+ }\n+\n+ .multiple-choice-options input[type='checkbox']:checked,\n+ .multiple-choice-options input[type='radio']:checked {\n+ background: var(--ph-survey-rating-active-bg-color);\n+ border-color: var(--ph-survey-rating-active-bg-color);\n+ }\n+\n+ .multiple-choice-options input[type='checkbox']:checked::after {\n+ content: '';\n+ position: absolute;\n+ left: 4px;\n+ width: 4px;\n+ height: 8px;\n+ border: solid white;\n+ border-width: 0 2px 2px 0;\n+ transform: rotate(45deg);\n+ }\n+\n+ .multiple-choice-options input[type='radio']:checked::after {\n+ content: '';\n+ position: absolute;\n+ left: 3.5px;\n+ top: 3.5px;\n+ width: 6px;\n+ height: 6px;\n+ border-radius: 50%;\n+ background: white;\n+ }\n+\n+ /* Rating Styles */\n+ .rating-text {\n+ display: flex;\n+ flex-direction: row;\n+ font-size: 0.8rem;\n+ justify-content: space-between;\n+ opacity: 0.7;\n+ }\n+\n+ .rating-options-number {\n+ display: grid;\n+ grid-auto-columns: 1fr;\n+ grid-auto-flow: column;\n+ border-radius: var(--ph-survey-border-radius);\n+ overflow: hidden;\n+ border: 2px solid var(--ph-survey-border-color);\n+ }\n+\n+ .ratings-number {\n+ padding: 0.875rem 0;\n+ border: none;\n+ background-color: var(--ph-survey-rating-button-color);\n+ border-right: 1px solid var(--ph-survey-border-color);\n+ text-align: center;\n+ cursor: pointer;\n+ color: var(--ph-survey-rating-button-text-color);\n+ font-weight: 600;\n+ transition: all 0.2s ease;\n+ font-family: var(--ph-survey-font-family);\n+ }\n+\n+ .ratings-number:last-of-type {\n+ border-right: 0;\n+ }\n+\n+ .ratings-number:hover {\n+ filter: brightness(0.95);\n+ }\n+\n+ .ratings-number.rating-active {\n+ background: var(--ph-survey-rating-active-bg-color);\n+ color: var(--ph-survey-rating-button-active-text-color);\n+ }\n+\n+ /* Button Styling */\n+ .form-submit {\n+ background: var(--ph-survey-submit-button-color);\n+ border: none;\n+ border-radius: var(--ph-survey-border-radius);\n+ padding: 0.875rem 2rem;\n+ font-size: 1rem;\n+ font-weight: 600;\n+ color: var(--ph-survey-submit-button-text-color);\n+ cursor: pointer;\n+ transition: all 0.2s ease;\n+ width: 100%;\n+ margin-top: 1rem;\n+ font-family: var(--ph-survey-font-family);\n+ }\n+\n+ .form-submit:hover:not([disabled]) {\n+ filter: brightness(0.9);\n+ transform: translateY(-1px);\n+ box-shadow: 0 4px 12px rgba(37, 99, 235, 0.3);\n+ }\n+\n+ .form-submit:active:not([disabled]) {\n+ transform: translateY(0);\n+ }\n+\n+ .form-submit[disabled] {\n+ opacity: var(--ph-survey-disabled-button-opacity);\n+ cursor: not-allowed;\n+ }\n+\n+ /* Footer Branding */\n+ .footer-branding {\n+ font-size: 11px;\n+ font-weight: 500;\n+ display: flex;\n+ justify-content: center;\n+ gap: 4px;\n+ align-items: center;\n+ text-decoration: none;\n+ opacity: 0.6;\n+ transition: all 0.2s ease;\n+ color: var(--ph-survey-text-subtle-color);\n+ font-family: var(--ph-survey-font-family);\n+ }\n+\n+ .footer-branding:hover {\n+ opacity: 1;\n+ }\n+\n+ .footer-branding a {\n+ text-decoration: none;\n+ color: inherit;\n+ }\n+\n+ /* Thank You Message */\n+ .thank-you-message {\n+ text-align: center;\n+ padding: 2rem;\n+ }\n+\n+ .thank-you-message-header {\n+ font-size: 1.5rem;\n+ font-weight: 700;\n+ color: var(--ph-survey-text-primary-color);\n+ margin: 0 0 1rem 0;\n+ }\n+\n+ .thank-you-message-body {\n+ font-size: 1rem;\n+ color: var(--ph-survey-text-subtle-color);\n+ opacity: 0.8;\n+ }\n+\n+ /* Scrollbar Styling */\n+ .multiple-choice-options::-webkit-scrollbar {\n+ width: 6px;\n+ }\n+\n+ .multiple-choice-options::-webkit-scrollbar-track {\n+ background: #f1f5f9;\n+ border-radius: 3px;\n+ }\n+\n+ .multiple-choice-options::-webkit-scrollbar-thumb {\n+ background: #cbd5e1;\n+ border-radius: 3px;\n+ }\n+\n+ .multiple-choice-options::-webkit-scrollbar-thumb:hover {\n+ background: #94a3b8;\n+ }\n+\n+ /* Loading State */\n+ .loading {\n+ text-align: center;\n+ padding: 3rem 2rem;\n+ color: var(--ph-survey-text-subtle-color);\n+ display: flex;\n+ flex-direction: column;\n+ align-items: center;\n+ justify-content: center;\n+ flex: 1;\n+ }\n+\n+ .loading-spinner {\n+ display: inline-block;\n+ width: 32px;\n+ height: 32px;\n+ border: 3px solid #e5e7eb;\n+ border-top: 3px solid var(--ph-survey-rating-active-bg-color);\n+ border-radius: 50%;\n+ animation: spin 1s linear infinite;\n+ margin-bottom: 1rem;\n+ }\n+\n+ .loading-text {\n+ font-size: 1.125rem;\n+ font-weight: 500;\n+ }\n+\n+ /* Hide loading when survey is rendered */\n+ #posthog-survey-container:has(.ph-survey) .loading {\n+ display: none;\n+ }\n+\n+ /* Animations */\n+ @keyframes spin {\n+ 0% {\n+ transform: rotate(0deg);\n+ }\n+\n+ 100% {\n+ transform: rotate(360deg);\n+ }\n+ }\n+\n+ @keyframes slideUp {\n+ from {\n+ opacity: 0;\n+ transform: translateY(30px);\n+ }\n+\n+ to {\n+ opacity: 1;\n+ transform: translateY(0);\n+ }\n+ }\n+\n+ /* Responsive Design */\n+ @media (max-width: 768px) {\n+ .main-container {\n+ padding: 0.5rem;\n+ }\n+\n+ .survey-header {\n+ padding: 1.5rem 1.5rem 1.25rem;\n+ }\n+\n+ .survey-title {\n+ font-size: 1.5rem;\n+ }\n+\n+ .survey-description {\n+ font-size: 0.9rem;\n+ }\n+\n+ .survey-form,\n+ .thank-you-message {\n+ padding: 1.25rem 1.5rem;\n+ }\n+\n+ .multiple-choice-options {\n+ max-height: 256px;\n+ }\n+ }\n+\n+ @media (max-height: 700px) {\n+ .main-container {\n+ padding: 0.75rem;\n+ }\n+\n+ .survey-header {\n+ padding: 1.25rem 2rem 1rem;\n+ }\n+\n+ .survey-title {\n+ font-size: 1.5rem;\n+ margin-bottom: 0.25rem;\n+ }\n+\n+ .survey-description {\n+ font-size: 0.9rem;\n+ }\n+\n+ .survey-form,\n+ .thank-you-message {\n+ padding: 1.25rem 2rem;\n+ }\n+ }\n+\n+ /* Utility classes */\n+ .sr-only {\n+ position: absolute;\n+ width: 1px;\n+ height: 1px;\n+ padding: 0;\n+ margin: -1px;\n+ overflow: hidden;\n+ clip: rect(0, 0, 0, 0);\n+ white-space: nowrap;\n+ border: 0;\n+ }\n+\n+ /* Motion preferences */\n+ @media (prefers-reduced-motion: reduce) {\n+ * {\n+ animation-duration: 0.01ms !important;\n+ animation-iteration-count: 1 !important;\n+ transition-duration: 0.01ms !important;\n+ }\n+ }\n+ </style>\n+</head>\n+\n+<body>\n+ <div class=\"main-container\">\n+ <div class=\"survey-card\">\n+ <div class=\"survey-header\">\n+ <h1 class=\"survey-title\">{{ name }}</h1>\n+ </div>\n+\n+ <div class=\"survey-content\">\n+ <div id=\"posthog-survey-container\">\n+ <div class=\"loading\">\n+ <div class=\"loading-spinner\"></div>\n+ <div class=\"loading-text\">Loading survey...</div>\n+ </div>\n+ </div>\n+ </div>\n+ </div>\n+ </div>\n+\n+ <!-- PostHog JavaScript -->\n+ <script>\n+ // Project configuration from Django context\n+ window.projectConfig = {{ project_config_json | safe }};\n+ window.surveyName = \"{{ name }}\";\n+ window.surveyId = \"{{ id }}\";\n+ window.surveyAppearance = {{ appearance | safe }};\n+\n+ const BLACK_TEXT_COLOR = '#020617'\n+\n+ function hex2rgb(c) {\n+ if (c[0] === '#') {\n+ const hexColor = c.replace(/^#/, '')\n+ const r = parseInt(hexColor.slice(0, 2), 16)\n+ const g = parseInt(hexColor.slice(2, 4), 16)\n+ const b = parseInt(hexColor.slice(4, 6), 16)\n+ return 'rgb(' + r + ',' + g + ',' + b + ')'\n+ }\n+ return 'rgb(255, 255, 255)'\n+ }\n+\n+\n+ function nameToHex(name) {\n+ return {\n+ aliceblue: '#f0f8ff',\n+ antiquewhite: '#faebd7',\n+ aqua: '#00ffff',\n+ aquamarine: '#7fffd4',\n+ azure: '#f0ffff',\n+ beige: '#f5f5dc',\n+ bisque: '#ffe4c4',\n+ black: '#000000',\n+ blanchedalmond: '#ffebcd',\n+ blue: '#0000ff',\n+ blueviolet: '#8a2be2',\n+ brown: '#a52a2a',\n+ burlywood: '#deb887',\n+ cadetblue: '#5f9ea0',\n+ chartreuse: '#7fff00',\n+ chocolate: '#d2691e',\n+ coral: '#ff7f50',\n+ cornflowerblue: '#6495ed',\n+ cornsilk: '#fff8dc',\n+ crimson: '#dc143c',\n+ cyan: '#00ffff',\n+ darkblue: '#00008b',\n+ darkcyan: '#008b8b',\n+ darkgoldenrod: '#b8860b',\n+ darkgray: '#a9a9a9',\n+ darkgreen: '#006400',\n+ darkkhaki: '#bdb76b',\n+ darkmagenta: '#8b008b',\n+ darkolivegreen: '#556b2f',\n+ darkorange: '#ff8c00',\n+ darkorchid: '#9932cc',\n+ darkred: '#8b0000',\n+ darksalmon: '#e9967a',\n+ darkseagreen: '#8fbc8f',\n+ darkslateblue: '#483d8b',\n+ darkslategray: '#2f4f4f',\n+ darkturquoise: '#00ced1',\n+ darkviolet: '#9400d3',\n+ deeppink: '#ff1493',\n+ deepskyblue: '#00bfff',\n+ dimgray: '#696969',\n+ dodgerblue: '#1e90ff',\n+ firebrick: '#b22222',\n+ floralwhite: '#fffaf0',\n+ forestgreen: '#228b22',\n+ fuchsia: '#ff00ff',\n+ gainsboro: '#dcdcdc',\n+ ghostwhite: '#f8f8ff',\n+ gold: '#ffd700',\n+ goldenrod: '#daa520',\n+ gray: '#808080',\n+ green: '#008000',\n+ greenyellow: '#adff2f',\n+ honeydew: '#f0fff0',\n+ hotpink: '#ff69b4',\n+ 'indianred ': '#cd5c5c',\n+ indigo: '#4b0082',\n+ ivory: '#fffff0',\n+ khaki: '#f0e68c',\n+ lavender: '#e6e6fa',\n+ lavenderblush: '#fff0f5',\n+ lawngreen: '#7cfc00',\n+ lemonchiffon: '#fffacd',\n+ lightblue: '#add8e6',\n+ lightcoral: '#f08080',\n+ lightcyan: '#e0ffff',\n+ lightgoldenrodyellow: '#fafad2',\n+ lightgrey: '#d3d3d3',\n+ lightgreen: '#90ee90',\n+ lightpink: '#ffb6c1',\n+ lightsalmon: '#ffa07a',\n+ lightseagreen: '#20b2aa',\n+ lightskyblue: '#87cefa',\n+ lightslategray: '#778899',\n+ lightsteelblue: '#b0c4de',\n+ lightyellow: '#ffffe0',\n+ lime: '#00ff00',\n+ limegreen: '#32cd32',\n+ linen: '#faf0e6',\n+ magenta: '#ff00ff',\n+ maroon: '#800000',\n+ mediumaquamarine: '#66cdaa',\n+ mediumblue: '#0000cd',\n+ mediumorchid: '#ba55d3',\n+ mediumpurple: '#9370d8',\n+ mediumseagreen: '#3cb371',\n+ mediumslateblue: '#7b68ee',\n+ mediumspringgreen: '#00fa9a',\n+ mediumturquoise: '#48d1cc',\n+ mediumvioletred: '#c71585',\n+ midnightblue: '#191970',\n+ mintcream: '#f5fffa',\n+ mistyrose: '#ffe4e1',\n+ moccasin: '#ffe4b5',\n+ navajowhite: '#ffdead',\n+ navy: '#000080',\n+ oldlace: '#fdf5e6',\n+ olive: '#808000',\n+ olivedrab: '#6b8e23',\n+ orange: '#ffa500',\n+ orangered: '#ff4500',\n+ orchid: '#da70d6',\n+ palegoldenrod: '#eee8aa',\n+ palegreen: '#98fb98',\n+ paleturquoise: '#afeeee',\n+ palevioletred: '#d87093',\n+ papayawhip: '#ffefd5',\n+ peachpuff: '#ffdab9',\n+ peru: '#cd853f',\n+ pink: '#ffc0cb',\n+ plum: '#dda0dd',\n+ powderblue: '#b0e0e6',\n+ purple: '#800080',\n+ red: '#ff0000',\n+ rosybrown: '#bc8f8f',\n+ royalblue: '#4169e1',\n+ saddlebrown: '#8b4513',\n+ salmon: '#fa8072',\n+ sandybrown: '#f4a460',\n+ seagreen: '#2e8b57',\n+ seashell: '#fff5ee',\n+ sienna: '#a0522d',\n+ silver: '#c0c0c0',\n+ skyblue: '#87ceeb',\n+ slateblue: '#6a5acd',\n+ slategray: '#708090',\n+ snow: '#fffafa',\n+ springgreen: '#00ff7f',\n+ steelblue: '#4682b4',\n+ tan: '#d2b48c',\n+ teal: '#008080',\n+ thistle: '#d8bfd8',\n+ tomato: '#ff6347',\n+ turquoise: '#40e0d0',\n+ violet: '#ee82ee',\n+ wheat: '#f5deb3',\n+ white: '#ffffff',\n+ whitesmoke: '#f5f5f5',\n+ yellow: '#ffff00',\n+ yellowgreen: '#9acd32',\n+ }[name.toLowerCase()]\n+ }\n+\n+ function getContrastingTextColor(color) {\n+ let rgb\n+ if (color[0] === '#') {\n+ rgb = hex2rgb(color)\n+ }\n+ if (color.startsWith('rgb')) {\n+ rgb = color\n+ }\n+ // otherwise it's a color name\n+ const nameColorToHex = nameToHex(color)\n+ if (nameColorToHex) {\n+ rgb = hex2rgb(nameColorToHex)\n+ }\n+ if (!rgb) {\n+ return BLACK_TEXT_COLOR\n+ }\n+ const colorMatch = rgb.match(/^rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)(?:,\\s*(\\d+(?:\\.\\d+)?))?\\)$/)\n+ if (colorMatch) {\n+ const r = parseInt(colorMatch[1])\n+ const g = parseInt(colorMatch[2])\n+ const b = parseInt(colorMatch[3])\n+ const hsp = Math.sqrt(0.299 * (r * r) + 0.587 * (g * g) + 0.114 * (b * b))\n+ return hsp > 127.5 ? BLACK_TEXT_COLOR : 'white'\n+ }\n+ return BLACK_TEXT_COLOR\n+ }\n+\n+ function colorToRgbaWithOpacity(color, opacity = 0.25) {\n+ let rgb\n+\n+ // Handle hex colors\n+ if (color[0] === '#') {\n+ rgb = hex2rgb(color)\n+ }\n+ // Handle rgb/rgba colors\n+ else if (color.startsWith('rgb')) {\n+ rgb = color\n+ }\n+ // Handle color names\n+ else {\n+ const nameColorToHex = nameToHex(color)\n+ if (nameColorToHex) {\n+ rgb = hex2rgb(nameColorToHex)\n+ }\n+ }\n+\n+ if (!rgb) {\n+ return `rgba(255, 255, 255, ${opacity})` // fallback to white with opacity\n+ }\n+\n+ const colorMatch = rgb.match(/^rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)(?:,\\s*(\\d+(?:\\.\\d+)?))?\\)$/)\n+ if (colorMatch) {\n+ const r = parseInt(colorMatch[1])\n+ const g = parseInt(colorMatch[2])\n+ const b = parseInt(colorMatch[3])\n+ return `rgba(${r}, ${g}, ${b}, ${opacity})`\n+ }\n+\n+ return `rgba(255, 255, 255, ${opacity})` // fallback\n+ }\n+\n+\n+ // Apply survey appearance settings as CSS variables\n+ function applySurveyAppearance(appearance) {\n+ if (!appearance) return;\n+\n+ const root = document.documentElement;\n+\n+ // Apply custom appearance settings\n+ if (appearance.backgroundColor) {\n+ // Apply to body and header instead of survey container\n+ // Use 25% opacity for body background for a softer effect\n+ root.style.setProperty('--ph-survey-body-background', colorToRgbaWithOpacity(appearance.backgroundColor, 0.25));\n+ root.style.setProperty('--ph-survey-header-background', appearance.backgroundColor);\n+ root.style.setProperty('--ph-survey-header-text-color', getContrastingTextColor(appearance.backgroundColor));\n+ }\n+\n+ if (appearance.submitButtonColor) {\n+ root.style.setProperty('--ph-survey-submit-button-color', appearance.submitButtonColor);\n+ root.style.setProperty('--ph-survey-submit-button-text-color',\n+ appearance.submitButtonTextColor || getContrastingTextColor(appearance.submitButtonColor));\n+ }\n+\n+ if (appearance.ratingButtonColor) {\n+ root.style.setProperty('--ph-survey-rating-button-color', appearance.ratingButtonColor);\n+ root.style.setProperty('--ph-survey-rating-button-text-color', getContrastingTextColor(appearance.ratingButtonColor));\n+ }\n+\n+ if (appearance.ratingButtonActiveColor) {\n+ root.style.setProperty('--ph-survey-rating-active-bg-color', appearance.ratingButtonActiveColor);\n+ root.style.setProperty('--ph-survey-rating-button-active-text-color', getContrastingTextColor(appearance.ratingButtonActiveColor));\n+ }\n+\n+ if (appearance.borderColor) {\n+ root.style.setProperty('--ph-survey-border-color', appearance.borderColor);\n+ }\n+\n+ if (appearance.borderRadius) {\n+ root.style.setProperty('--ph-survey-border-radius', appearance.borderRadius);\n+ root.style.setProperty('--ph-survey-card-border-radius', appearance.borderRadius);\n+ }\n+\n+ if (appearance.inputBackground) {\n+ root.style.setProperty('--ph-survey-input-background', appearance.inputBackground);\n+ }\n+\n+ if (appearance.textSubtleColor) {\n+ root.style.setProperty('--ph-survey-text-subtle-color', appearance.textSubtleColor);\n+ }\n+\n+ if (appearance.disabledButtonOpacity) {\n+ root.style.setProperty('--ph-survey-disabled-button-opacity', appearance.disabledButtonOpacity);\n+ }\n+\n+ // Properties not suitable for external surveys (ignored):\n+ // - zIndex: not relevant for full page\n+ // - maxWidth: we manage our own layout\n+ // - position: not relevant for full page\n+ // - boxShadow: we have our own design\n+ // - boxPadding: we have our own padding\n+ // - fontFamily: we have our own font stack\n+ // - whiteLabel: not relevant for this context\n+ // - placeholder: handled by PostHog survey rendering\n+ // - shuffleQuestions: behavioral setting, not appearance\n+ // - thankYouMessageHeader/thankYouMessageDescription: handled by PostHog survey rendering\n+ // - displayThankYouMessage: handled by PostHog survey rendering\n+ }\n+\n+ // Apply survey appearance if available\n+ if (window.surveyAppearance) {\n+ applySurveyAppearance(window.surveyAppearance);\n+ }\n+\n+ // Load PostHog from CDN",
|
|
"comment_created_at": "2025-07-15T02:23:54+00:00",
|
|
"comment_author": "lucasheriques",
|
|
"comment_body": "actually this is not correct. We're not loading the usual posthog React app. We're just rendering a HTML page (this one you commented). So we need to load the snippet here regardless, since we also need to init it according to the customer's config ",
|
|
"pr_file_module": null
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"discussion_id": "2218491245",
|
|
"pr_number": 33948,
|
|
"pr_file": "posthog/templates/surveys/public_survey.html",
|
|
"created_at": "2025-07-21T08:16:54+00:00",
|
|
"commented_code": "+<!DOCTYPE html>\n+<html lang=\"en\">\n+\n+<head>\n+ <meta charset=\"UTF-8\">\n+ <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n+ <title>{{ name }}</title>\n+ <meta name=\"description\" content=\"Take our survey: {{ name }}\">\n+ <style>\n+ /* CSS Variables */\n+ :root {\n+ --ph-survey-font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', Helvetica, Arial, sans-serif;\n+ --ph-survey-border-color: #e5e7eb;\n+ --ph-survey-border-radius: 8px;\n+ --ph-survey-card-border-radius: 16px;\n+ --ph-survey-body-background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n+ --ph-survey-header-background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n+ --ph-survey-header-text-color: white;\n+ --ph-survey-background-color: #ffffff;\n+ --ph-survey-text-primary-color: #111827;\n+ --ph-survey-text-subtle-color: #6b7280;\n+ --ph-survey-input-background: #ffffff;\n+ --ph-survey-submit-button-color: #2563eb;\n+ --ph-survey-submit-button-text-color: white;\n+ --ph-survey-rating-button-color: #f8fafc;\n+ --ph-survey-rating-active-bg-color: #2563eb;\n+ --ph-survey-rating-button-text-color: #374151;\n+ --ph-survey-rating-button-active-text-color: white;\n+ --ph-survey-disabled-button-opacity: 0.6;\n+ --ph-survey-focus-ring: 0 0 0 3px rgba(37, 99, 235, 0.1);\n+ --ph-survey-box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);\n+ }\n+\n+ * {\n+ box-sizing: border-box;\n+ }\n+\n+ /* Base Layout */\n+ body {\n+ font-family: var(--ph-survey-font-family);\n+ margin: 0;\n+ padding: 0;\n+ background: var(--ph-survey-body-background);\n+ min-height: 100vh;\n+ line-height: 1.6;\n+ color: var(--ph-survey-text-primary-color);\n+ font-size: 16px;\n+ -webkit-font-smoothing: antialiased;\n+ }\n+\n+ .main-container {\n+ min-height: 100vh;\n+ display: flex;\n+ align-items: center;\n+ justify-content: center;\n+ padding: 1rem;\n+ box-sizing: border-box;\n+ }\n+\n+ .survey-card {\n+ background: white;\n+ border-radius: var(--ph-survey-card-border-radius);\n+ box-shadow: var(--ph-survey-box-shadow);\n+ max-width: 720px;\n+ width: 100%;\n+ overflow: hidden;\n+ max-height: 90vh;\n+ display: flex;\n+ flex-direction: column;\n+ animation: slideUp 0.6s ease-out;\n+ }\n+\n+ /* Survey Header */\n+ .survey-header {\n+ background: var(--ph-survey-header-background);\n+ color: var(--ph-survey-header-text-color);\n+ padding: 1.75rem 2rem 1.5rem;\n+ text-align: center;\n+ flex-shrink: 0;\n+ }\n+\n+ .survey-title {\n+ font-size: 1.75rem;\n+ font-weight: 700;\n+ margin: 0;\n+ }\n+\n+ .survey-description {\n+ font-size: 1rem;\n+ margin: 0;\n+ opacity: 0.9;\n+ line-height: 1.4;\n+ }\n+\n+ /* Survey Content */\n+ .survey-content {\n+ flex: 1;\n+ display: flex;\n+ flex-direction: column;\n+ min-height: 0;\n+ }\n+\n+ .survey-box {\n+ display: flex;\n+ flex-direction: column;\n+ gap: 1rem;\n+ flex: 1;\n+ min-height: 0;\n+ }\n+\n+ .bottom-section {\n+ display: flex;\n+ flex-direction: column;\n+ gap: 0.75rem;\n+ }\n+\n+ .survey-form,\n+ .thank-you-message {\n+ width: 100%;\n+ margin: 0;\n+ border: none;\n+ border-radius: 0;\n+ box-shadow: none;\n+ background: white;\n+ padding: 1.5rem 2rem;\n+ display: flex;\n+ flex-direction: column;\n+ justify-content: center;\n+ min-height: 0;\n+ }\n+\n+ /* Question Styling */\n+ .survey-question {\n+ font-size: 1.25rem;\n+ font-weight: 600;\n+ color: var(--ph-survey-text-primary-color);\n+ line-height: 1.4;\n+ margin: 0;\n+ }\n+\n+ .survey-question-description {\n+ font-size: 1rem;\n+ color: var(--ph-survey-text-subtle-color);\n+ margin-top: 0.25rem;\n+ margin-bottom: 1.25rem;\n+ }\n+\n+ .question-container,\n+ .thank-you-message {\n+ display: flex;\n+ flex-direction: column;\n+ justify-content: center;\n+ gap: 8px;\n+ }\n+\n+ .response-choice {\n+ display: flex;\n+ gap: 8px;\n+ align-items: center;\n+ }\n+\n+\n+ /* Input Styling */\n+ textarea,\n+ input[type='text'] {\n+ border: 2px solid var(--ph-survey-border-color);\n+ border-radius: var(--ph-survey-border-radius);\n+ padding: 1rem;\n+ font-size: 1rem;\n+ line-height: 1.5;\n+ transition: all 0.2s ease;\n+ background: var(--ph-survey-input-background);\n+ color: var(--ph-survey-text-primary-color);\n+ width: 100%;\n+ font-family: var(--ph-survey-font-family);\n+ }\n+\n+ textarea:focus,\n+ input[type='text']:focus {\n+ outline: none;\n+ border-color: var(--ph-survey-rating-active-bg-color);\n+ box-shadow: var(--ph-survey-focus-ring);\n+ }\n+\n+ textarea:hover:not(:focus),\n+ input[type='text']:hover:not(:focus) {\n+ border-color: var(--ph-survey-rating-active-bg-color);\n+ }\n+\n+ /* Multiple Choice Options */\n+ .multiple-choice-options {\n+ display: flex;\n+ flex-direction: column;\n+ gap: 0.625rem;\n+ flex: 1;\n+ justify-content: flex-start;\n+ overflow-y: auto;\n+ max-height: 400px;\n+ padding-right: 0.5rem;\n+ margin: 0;\n+ padding-left: 0;\n+ border: none;\n+ }\n+\n+ /* Fieldset styling */\n+ fieldset {\n+ border: none;\n+ margin: 0;\n+ padding: 0;\n+ }\n+\n+ .multiple-choice-options label {\n+ border: 2px solid var(--ph-survey-border-color);\n+ border-radius: var(--ph-survey-border-radius);\n+ padding: 0.875rem 1.25rem;\n+ cursor: pointer;\n+ transition: all 0.2s ease;\n+ background: white;\n+ font-size: 1rem;\n+ min-height: 56px;\n+ display: flex;\n+ align-items: center;\n+ gap: 12px;\n+ flex-shrink: 0;\n+ color: var(--ph-survey-text-primary-color);\n+ font-family: var(--ph-survey-font-family);\n+ }\n+\n+ .choice-option-open {\n+ flex-wrap: wrap;\n+ }\n+\n+ .multiple-choice-options label:hover:not(:has(input:checked)) {\n+ border-color: #d1d5db;\n+ background: #f9fafb;\n+ }\n+\n+ .multiple-choice-options label:has(input:checked) {\n+ border-color: var(--ph-survey-rating-active-bg-color);\n+ background: #eff6ff;\n+ }\n+\n+ .multiple-choice-options input[type='checkbox'],\n+ .multiple-choice-options input[type='radio'] {\n+ appearance: none;\n+ width: 1rem;\n+ height: 1rem;\n+ background: var(--ph-survey-input-background);\n+ border: 1.5px solid var(--ph-survey-border-color);\n+ cursor: pointer;\n+ border-radius: 3px;\n+ flex-shrink: 0;\n+ transition: all 0.2s ease;\n+ position: relative;\n+ margin: 0;\n+ }\n+\n+ .multiple-choice-options input[type='radio'] {\n+ border-radius: 50%;\n+ }\n+\n+ .multiple-choice-options input[type='checkbox']:hover,\n+ .multiple-choice-options input[type='radio']:hover {\n+ border-color: var(--ph-survey-rating-active-bg-color);\n+ transform: scale(1.05);\n+ }\n+\n+ .multiple-choice-options input[type='checkbox']:checked,\n+ .multiple-choice-options input[type='radio']:checked {\n+ background: var(--ph-survey-rating-active-bg-color);\n+ border-color: var(--ph-survey-rating-active-bg-color);\n+ }\n+\n+ .multiple-choice-options input[type='checkbox']:checked::after {\n+ content: '';\n+ position: absolute;\n+ left: 4px;\n+ width: 4px;\n+ height: 8px;\n+ border: solid white;\n+ border-width: 0 2px 2px 0;\n+ transform: rotate(45deg);\n+ }\n+\n+ .multiple-choice-options input[type='radio']:checked::after {\n+ content: '';\n+ position: absolute;\n+ left: 3.5px;\n+ top: 3.5px;\n+ width: 6px;\n+ height: 6px;\n+ border-radius: 50%;\n+ background: white;\n+ }\n+\n+ /* Rating Styles */\n+ .rating-text {\n+ display: flex;\n+ flex-direction: row;\n+ font-size: 0.8rem;\n+ justify-content: space-between;\n+ opacity: 0.7;\n+ }\n+\n+ .rating-options-number {\n+ display: grid;\n+ grid-auto-columns: 1fr;\n+ grid-auto-flow: column;\n+ border-radius: var(--ph-survey-border-radius);\n+ overflow: hidden;\n+ border: 2px solid var(--ph-survey-border-color);\n+ }\n+\n+ .ratings-number {\n+ padding: 0.875rem 0;\n+ border: none;\n+ background-color: var(--ph-survey-rating-button-color);\n+ border-right: 1px solid var(--ph-survey-border-color);\n+ text-align: center;\n+ cursor: pointer;\n+ color: var(--ph-survey-rating-button-text-color);\n+ font-weight: 600;\n+ transition: all 0.2s ease;\n+ font-family: var(--ph-survey-font-family);\n+ }\n+\n+ .ratings-number:last-of-type {\n+ border-right: 0;\n+ }\n+\n+ .ratings-number:hover {\n+ filter: brightness(0.95);\n+ }\n+\n+ .ratings-number.rating-active {\n+ background: var(--ph-survey-rating-active-bg-color);\n+ color: var(--ph-survey-rating-button-active-text-color);\n+ }\n+\n+ /* Button Styling */\n+ .form-submit {\n+ background: var(--ph-survey-submit-button-color);\n+ border: none;\n+ border-radius: var(--ph-survey-border-radius);\n+ padding: 0.875rem 2rem;\n+ font-size: 1rem;\n+ font-weight: 600;\n+ color: var(--ph-survey-submit-button-text-color);\n+ cursor: pointer;\n+ transition: all 0.2s ease;\n+ width: 100%;\n+ margin-top: 1rem;\n+ font-family: var(--ph-survey-font-family);\n+ }\n+\n+ .form-submit:hover:not([disabled]) {\n+ filter: brightness(0.9);\n+ transform: translateY(-1px);\n+ box-shadow: 0 4px 12px rgba(37, 99, 235, 0.3);\n+ }\n+\n+ .form-submit:active:not([disabled]) {\n+ transform: translateY(0);\n+ }\n+\n+ .form-submit[disabled] {\n+ opacity: var(--ph-survey-disabled-button-opacity);\n+ cursor: not-allowed;\n+ }\n+\n+ /* Footer Branding */\n+ .footer-branding {\n+ font-size: 11px;\n+ font-weight: 500;\n+ display: flex;\n+ justify-content: center;\n+ gap: 4px;\n+ align-items: center;\n+ text-decoration: none;\n+ opacity: 0.6;\n+ transition: all 0.2s ease;\n+ color: var(--ph-survey-text-subtle-color);\n+ font-family: var(--ph-survey-font-family);\n+ }\n+\n+ .footer-branding:hover {\n+ opacity: 1;\n+ }\n+\n+ .footer-branding a {\n+ text-decoration: none;\n+ color: inherit;\n+ }\n+\n+ /* Thank You Message */\n+ .thank-you-message {\n+ text-align: center;\n+ padding: 2rem;\n+ }\n+\n+ .thank-you-message-header {\n+ font-size: 1.5rem;\n+ font-weight: 700;\n+ color: var(--ph-survey-text-primary-color);\n+ margin: 0 0 1rem 0;\n+ }\n+\n+ .thank-you-message-body {\n+ font-size: 1rem;\n+ color: var(--ph-survey-text-subtle-color);\n+ opacity: 0.8;\n+ }\n+\n+ /* Scrollbar Styling */\n+ .multiple-choice-options::-webkit-scrollbar {\n+ width: 6px;\n+ }\n+\n+ .multiple-choice-options::-webkit-scrollbar-track {\n+ background: #f1f5f9;\n+ border-radius: 3px;\n+ }\n+\n+ .multiple-choice-options::-webkit-scrollbar-thumb {\n+ background: #cbd5e1;\n+ border-radius: 3px;\n+ }\n+\n+ .multiple-choice-options::-webkit-scrollbar-thumb:hover {\n+ background: #94a3b8;\n+ }\n+\n+ /* Loading State */\n+ .loading {\n+ text-align: center;\n+ padding: 3rem 2rem;\n+ color: var(--ph-survey-text-subtle-color);\n+ display: flex;\n+ flex-direction: column;\n+ align-items: center;\n+ justify-content: center;\n+ flex: 1;\n+ }\n+\n+ .loading-spinner {\n+ display: inline-block;\n+ width: 32px;\n+ height: 32px;\n+ border: 3px solid #e5e7eb;\n+ border-top: 3px solid var(--ph-survey-rating-active-bg-color);\n+ border-radius: 50%;\n+ animation: spin 1s linear infinite;\n+ margin-bottom: 1rem;\n+ }\n+\n+ .loading-text {\n+ font-size: 1.125rem;\n+ font-weight: 500;\n+ }\n+\n+ /* Hide loading when survey is rendered */\n+ #posthog-survey-container:has(.ph-survey) .loading {\n+ display: none;\n+ }\n+\n+ /* Animations */\n+ @keyframes spin {\n+ 0% {\n+ transform: rotate(0deg);\n+ }\n+\n+ 100% {\n+ transform: rotate(360deg);\n+ }\n+ }\n+\n+ @keyframes slideUp {\n+ from {\n+ opacity: 0;\n+ transform: translateY(30px);\n+ }\n+\n+ to {\n+ opacity: 1;\n+ transform: translateY(0);\n+ }\n+ }\n+\n+ /* Responsive Design */\n+ @media (max-width: 768px) {\n+ .main-container {\n+ padding: 0.5rem;\n+ }\n+\n+ .survey-header {\n+ padding: 1.5rem 1.5rem 1.25rem;\n+ }\n+\n+ .survey-title {\n+ font-size: 1.5rem;\n+ }\n+\n+ .survey-description {\n+ font-size: 0.9rem;\n+ }\n+\n+ .survey-form,\n+ .thank-you-message {\n+ padding: 1.25rem 1.5rem;\n+ }\n+\n+ .multiple-choice-options {\n+ max-height: 256px;\n+ }\n+ }\n+\n+ @media (max-height: 700px) {\n+ .main-container {\n+ padding: 0.75rem;\n+ }\n+\n+ .survey-header {\n+ padding: 1.25rem 2rem 1rem;\n+ }\n+\n+ .survey-title {\n+ font-size: 1.5rem;\n+ margin-bottom: 0.25rem;\n+ }\n+\n+ .survey-description {\n+ font-size: 0.9rem;\n+ }\n+\n+ .survey-form,\n+ .thank-you-message {\n+ padding: 1.25rem 2rem;\n+ }\n+ }\n+\n+ /* Utility classes */\n+ .sr-only {\n+ position: absolute;\n+ width: 1px;\n+ height: 1px;\n+ padding: 0;\n+ margin: -1px;\n+ overflow: hidden;\n+ clip: rect(0, 0, 0, 0);\n+ white-space: nowrap;\n+ border: 0;\n+ }\n+\n+ /* Motion preferences */\n+ @media (prefers-reduced-motion: reduce) {\n+ * {\n+ animation-duration: 0.01ms !important;\n+ animation-iteration-count: 1 !important;\n+ transition-duration: 0.01ms !important;\n+ }\n+ }\n+ </style>\n+</head>\n+\n+<body>\n+ <div class=\"main-container\">\n+ <div class=\"survey-card\">\n+ <div class=\"survey-header\">\n+ <h1 class=\"survey-title\">{{ name }}</h1>\n+ </div>\n+\n+ <div class=\"survey-content\">\n+ <div id=\"posthog-survey-container\">\n+ <div class=\"loading\">\n+ <div class=\"loading-spinner\"></div>\n+ <div class=\"loading-text\">Loading survey...</div>\n+ </div>\n+ </div>\n+ </div>\n+ </div>\n+ </div>\n+\n+ <!-- PostHog JavaScript -->\n+ <script>\n+ // Project configuration from Django context\n+ window.projectConfig = {{ project_config_json | safe }};\n+ window.surveyName = \"{{ name }}\";\n+ window.surveyId = \"{{ id }}\";\n+ window.surveyAppearance = {{ appearance | safe }};\n+\n+ const BLACK_TEXT_COLOR = '#020617'\n+\n+ function hex2rgb(c) {\n+ if (c[0] === '#') {\n+ const hexColor = c.replace(/^#/, '')\n+ const r = parseInt(hexColor.slice(0, 2), 16)\n+ const g = parseInt(hexColor.slice(2, 4), 16)\n+ const b = parseInt(hexColor.slice(4, 6), 16)\n+ return 'rgb(' + r + ',' + g + ',' + b + ')'\n+ }\n+ return 'rgb(255, 255, 255)'\n+ }\n+\n+\n+ function nameToHex(name) {\n+ return {\n+ aliceblue: '#f0f8ff',\n+ antiquewhite: '#faebd7',\n+ aqua: '#00ffff',\n+ aquamarine: '#7fffd4',\n+ azure: '#f0ffff',\n+ beige: '#f5f5dc',\n+ bisque: '#ffe4c4',\n+ black: '#000000',\n+ blanchedalmond: '#ffebcd',\n+ blue: '#0000ff',\n+ blueviolet: '#8a2be2',\n+ brown: '#a52a2a',\n+ burlywood: '#deb887',\n+ cadetblue: '#5f9ea0',\n+ chartreuse: '#7fff00',\n+ chocolate: '#d2691e',\n+ coral: '#ff7f50',\n+ cornflowerblue: '#6495ed',\n+ cornsilk: '#fff8dc',\n+ crimson: '#dc143c',\n+ cyan: '#00ffff',\n+ darkblue: '#00008b',\n+ darkcyan: '#008b8b',\n+ darkgoldenrod: '#b8860b',\n+ darkgray: '#a9a9a9',\n+ darkgreen: '#006400',\n+ darkkhaki: '#bdb76b',\n+ darkmagenta: '#8b008b',\n+ darkolivegreen: '#556b2f',\n+ darkorange: '#ff8c00',\n+ darkorchid: '#9932cc',\n+ darkred: '#8b0000',\n+ darksalmon: '#e9967a',\n+ darkseagreen: '#8fbc8f',\n+ darkslateblue: '#483d8b',\n+ darkslategray: '#2f4f4f',\n+ darkturquoise: '#00ced1',\n+ darkviolet: '#9400d3',\n+ deeppink: '#ff1493',\n+ deepskyblue: '#00bfff',\n+ dimgray: '#696969',\n+ dodgerblue: '#1e90ff',\n+ firebrick: '#b22222',\n+ floralwhite: '#fffaf0',\n+ forestgreen: '#228b22',\n+ fuchsia: '#ff00ff',\n+ gainsboro: '#dcdcdc',\n+ ghostwhite: '#f8f8ff',\n+ gold: '#ffd700',\n+ goldenrod: '#daa520',\n+ gray: '#808080',\n+ green: '#008000',\n+ greenyellow: '#adff2f',\n+ honeydew: '#f0fff0',\n+ hotpink: '#ff69b4',\n+ 'indianred ': '#cd5c5c',\n+ indigo: '#4b0082',\n+ ivory: '#fffff0',\n+ khaki: '#f0e68c',\n+ lavender: '#e6e6fa',\n+ lavenderblush: '#fff0f5',\n+ lawngreen: '#7cfc00',\n+ lemonchiffon: '#fffacd',\n+ lightblue: '#add8e6',\n+ lightcoral: '#f08080',\n+ lightcyan: '#e0ffff',\n+ lightgoldenrodyellow: '#fafad2',\n+ lightgrey: '#d3d3d3',\n+ lightgreen: '#90ee90',\n+ lightpink: '#ffb6c1',\n+ lightsalmon: '#ffa07a',\n+ lightseagreen: '#20b2aa',\n+ lightskyblue: '#87cefa',\n+ lightslategray: '#778899',\n+ lightsteelblue: '#b0c4de',\n+ lightyellow: '#ffffe0',\n+ lime: '#00ff00',\n+ limegreen: '#32cd32',\n+ linen: '#faf0e6',\n+ magenta: '#ff00ff',\n+ maroon: '#800000',\n+ mediumaquamarine: '#66cdaa',\n+ mediumblue: '#0000cd',\n+ mediumorchid: '#ba55d3',\n+ mediumpurple: '#9370d8',\n+ mediumseagreen: '#3cb371',\n+ mediumslateblue: '#7b68ee',\n+ mediumspringgreen: '#00fa9a',\n+ mediumturquoise: '#48d1cc',\n+ mediumvioletred: '#c71585',\n+ midnightblue: '#191970',\n+ mintcream: '#f5fffa',\n+ mistyrose: '#ffe4e1',\n+ moccasin: '#ffe4b5',\n+ navajowhite: '#ffdead',\n+ navy: '#000080',\n+ oldlace: '#fdf5e6',\n+ olive: '#808000',\n+ olivedrab: '#6b8e23',\n+ orange: '#ffa500',\n+ orangered: '#ff4500',\n+ orchid: '#da70d6',\n+ palegoldenrod: '#eee8aa',\n+ palegreen: '#98fb98',\n+ paleturquoise: '#afeeee',\n+ palevioletred: '#d87093',\n+ papayawhip: '#ffefd5',\n+ peachpuff: '#ffdab9',\n+ peru: '#cd853f',\n+ pink: '#ffc0cb',\n+ plum: '#dda0dd',\n+ powderblue: '#b0e0e6',\n+ purple: '#800080',\n+ red: '#ff0000',\n+ rosybrown: '#bc8f8f',\n+ royalblue: '#4169e1',\n+ saddlebrown: '#8b4513',\n+ salmon: '#fa8072',\n+ sandybrown: '#f4a460',\n+ seagreen: '#2e8b57',\n+ seashell: '#fff5ee',\n+ sienna: '#a0522d',\n+ silver: '#c0c0c0',\n+ skyblue: '#87ceeb',\n+ slateblue: '#6a5acd',\n+ slategray: '#708090',\n+ snow: '#fffafa',\n+ springgreen: '#00ff7f',\n+ steelblue: '#4682b4',\n+ tan: '#d2b48c',\n+ teal: '#008080',\n+ thistle: '#d8bfd8',\n+ tomato: '#ff6347',\n+ turquoise: '#40e0d0',\n+ violet: '#ee82ee',\n+ wheat: '#f5deb3',\n+ white: '#ffffff',\n+ whitesmoke: '#f5f5f5',\n+ yellow: '#ffff00',\n+ yellowgreen: '#9acd32',\n+ }[name.toLowerCase()]\n+ }\n+\n+ function getContrastingTextColor(color) {\n+ let rgb\n+ if (color[0] === '#') {\n+ rgb = hex2rgb(color)\n+ }\n+ if (color.startsWith('rgb')) {\n+ rgb = color\n+ }\n+ // otherwise it's a color name\n+ const nameColorToHex = nameToHex(color)\n+ if (nameColorToHex) {\n+ rgb = hex2rgb(nameColorToHex)\n+ }\n+ if (!rgb) {\n+ return BLACK_TEXT_COLOR\n+ }\n+ const colorMatch = rgb.match(/^rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)(?:,\\s*(\\d+(?:\\.\\d+)?))?\\)$/)\n+ if (colorMatch) {\n+ const r = parseInt(colorMatch[1])\n+ const g = parseInt(colorMatch[2])\n+ const b = parseInt(colorMatch[3])\n+ const hsp = Math.sqrt(0.299 * (r * r) + 0.587 * (g * g) + 0.114 * (b * b))\n+ return hsp > 127.5 ? BLACK_TEXT_COLOR : 'white'\n+ }\n+ return BLACK_TEXT_COLOR\n+ }\n+\n+ function colorToRgbaWithOpacity(color, opacity = 0.25) {\n+ let rgb\n+\n+ // Handle hex colors\n+ if (color[0] === '#') {\n+ rgb = hex2rgb(color)\n+ }\n+ // Handle rgb/rgba colors\n+ else if (color.startsWith('rgb')) {\n+ rgb = color\n+ }\n+ // Handle color names\n+ else {\n+ const nameColorToHex = nameToHex(color)\n+ if (nameColorToHex) {\n+ rgb = hex2rgb(nameColorToHex)\n+ }\n+ }\n+\n+ if (!rgb) {\n+ return `rgba(255, 255, 255, ${opacity})` // fallback to white with opacity\n+ }\n+\n+ const colorMatch = rgb.match(/^rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)(?:,\\s*(\\d+(?:\\.\\d+)?))?\\)$/)\n+ if (colorMatch) {\n+ const r = parseInt(colorMatch[1])\n+ const g = parseInt(colorMatch[2])\n+ const b = parseInt(colorMatch[3])\n+ return `rgba(${r}, ${g}, ${b}, ${opacity})`\n+ }\n+\n+ return `rgba(255, 255, 255, ${opacity})` // fallback\n+ }\n+\n+\n+ // Apply survey appearance settings as CSS variables\n+ function applySurveyAppearance(appearance) {\n+ if (!appearance) return;\n+\n+ const root = document.documentElement;\n+\n+ // Apply custom appearance settings\n+ if (appearance.backgroundColor) {\n+ // Apply to body and header instead of survey container\n+ // Use 25% opacity for body background for a softer effect\n+ root.style.setProperty('--ph-survey-body-background', colorToRgbaWithOpacity(appearance.backgroundColor, 0.25));\n+ root.style.setProperty('--ph-survey-header-background', appearance.backgroundColor);\n+ root.style.setProperty('--ph-survey-header-text-color', getContrastingTextColor(appearance.backgroundColor));\n+ }\n+\n+ if (appearance.submitButtonColor) {\n+ root.style.setProperty('--ph-survey-submit-button-color', appearance.submitButtonColor);\n+ root.style.setProperty('--ph-survey-submit-button-text-color',\n+ appearance.submitButtonTextColor || getContrastingTextColor(appearance.submitButtonColor));\n+ }\n+\n+ if (appearance.ratingButtonColor) {\n+ root.style.setProperty('--ph-survey-rating-button-color', appearance.ratingButtonColor);\n+ root.style.setProperty('--ph-survey-rating-button-text-color', getContrastingTextColor(appearance.ratingButtonColor));\n+ }\n+\n+ if (appearance.ratingButtonActiveColor) {\n+ root.style.setProperty('--ph-survey-rating-active-bg-color', appearance.ratingButtonActiveColor);\n+ root.style.setProperty('--ph-survey-rating-button-active-text-color', getContrastingTextColor(appearance.ratingButtonActiveColor));\n+ }\n+\n+ if (appearance.borderColor) {\n+ root.style.setProperty('--ph-survey-border-color', appearance.borderColor);\n+ }\n+\n+ if (appearance.borderRadius) {\n+ root.style.setProperty('--ph-survey-border-radius', appearance.borderRadius);\n+ root.style.setProperty('--ph-survey-card-border-radius', appearance.borderRadius);\n+ }\n+\n+ if (appearance.inputBackground) {\n+ root.style.setProperty('--ph-survey-input-background', appearance.inputBackground);\n+ }\n+\n+ if (appearance.textSubtleColor) {\n+ root.style.setProperty('--ph-survey-text-subtle-color', appearance.textSubtleColor);\n+ }\n+\n+ if (appearance.disabledButtonOpacity) {\n+ root.style.setProperty('--ph-survey-disabled-button-opacity', appearance.disabledButtonOpacity);\n+ }\n+\n+ // Properties not suitable for external surveys (ignored):\n+ // - zIndex: not relevant for full page\n+ // - maxWidth: we manage our own layout\n+ // - position: not relevant for full page\n+ // - boxShadow: we have our own design\n+ // - boxPadding: we have our own padding\n+ // - fontFamily: we have our own font stack\n+ // - whiteLabel: not relevant for this context\n+ // - placeholder: handled by PostHog survey rendering\n+ // - shuffleQuestions: behavioral setting, not appearance\n+ // - thankYouMessageHeader/thankYouMessageDescription: handled by PostHog survey rendering\n+ // - displayThankYouMessage: handled by PostHog survey rendering\n+ }\n+\n+ // Apply survey appearance if available\n+ if (window.surveyAppearance) {\n+ applySurveyAppearance(window.surveyAppearance);\n+ }\n+\n+ // Load PostHog from CDN\n+ !function (t, e) { var o, n, p, r; e.__SV || (window.posthog = e, e._i = [], e.init = function (i, s, a) { function g(t, e) { var o = e.split(\".\"); 2 == o.length && (t = t[o[0]], e = o[1]), t[e] = function () { t.push([e].concat(Array.prototype.slice.call(arguments, 0))) } } (p = t.createElement(\"script\")).type = \"text/javascript\", p.crossOrigin = \"anonymous\", p.async = !0, p.src = s.api_host.replace(\".i.posthog.com\", \"-assets.i.posthog.com\") + \"/static/array.js\", (r = t.getElementsByTagName(\"script\")[0]).parentNode.insertBefore(p, r); var u = e; for (void 0 !== a ? u = e[a] = [] : a = \"posthog\", u.people = u.people || [], u.toString = function (t) { var e = \"posthog\"; return \"posthog\" !== a && (e += \".\" + a), t || (e += \" (stub)\"), e }, u.people.toString = function () { return u.toString(1) + \".people (stub)\" }, o = \"init Ie Ts Ms Ee Es Rs capture Ge calculateEventProperties Os register register_once register_for_session unregister unregister_for_session js getFeatureFlag getFeatureFlagPayload isFeatureEnabled reloadFeatureFlags updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures on onFeatureFlags onSurveysLoaded onSessionId getSurveys getActiveMatchingSurveys renderSurvey canRenderSurvey canRenderSurveyAsync identify setPersonProperties group resetGroups setPersonPropertiesForFlags resetPersonPropertiesForFlags setGroupPropertiesForFlags resetGroupPropertiesForFlags reset get_distinct_id getGroups get_session_id get_session_replay_url alias set_config startSessionRecording stopSessionRecording sessionRecordingStarted captureException loadToolbar get_property getSessionProperty Ds Fs createPersonProfile Ls Ps opt_in_capturing opt_out_capturing has_opted_in_capturing has_opted_out_capturing clear_opt_in_out_capturing Cs debug I As getPageViewId captureTraceFeedback captureTraceMetric\".split(\" \"), n = 0; n < o.length; n++)g(u, o[n]); e._i.push([i, s, a]) }, e.__SV = 1) }(document, window.posthog || []);\n+\n+ // Initialize PostHog with project configuration\n+ const config = {\n+ api_host: window.projectConfig.api_host,\n+ disable_surveys_automatic_display: true,\n+ debug: true,\n+ advanced_disable_toolbar_metrics: true,\n+ persistence: 'localStorage',\n+ capture_pageview: false, // Don't capture pageviews for survey pages\n+ capture_pageleave: false\n+ };\n+\n+ // Add ui_host if available (for reverse proxy setups)\n+ if (window.projectConfig.ui_host) {\n+ config.ui_host = window.projectConfig.ui_host;\n+ }\n+\n+ posthog.init(window.projectConfig.token, config);\n+ const distinctId = new URLSearchParams(window.location.search).get('distinct_id');\n+ if (distinctId) {\n+ posthog.identify(distinctId);\n+ }",
|
|
"repo_full_name": "PostHog/posthog",
|
|
"discussion_comments": [
|
|
{
|
|
"comment_id": "2218491245",
|
|
"repo_full_name": "PostHog/posthog",
|
|
"pr_number": 33948,
|
|
"pr_file": "posthog/templates/surveys/public_survey.html",
|
|
"discussion_id": "2218491245",
|
|
"commented_code": "@@ -0,0 +1,939 @@\n+<!DOCTYPE html>\n+<html lang=\"en\">\n+\n+<head>\n+ <meta charset=\"UTF-8\">\n+ <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n+ <title>{{ name }}</title>\n+ <meta name=\"description\" content=\"Take our survey: {{ name }}\">\n+ <style>\n+ /* CSS Variables */\n+ :root {\n+ --ph-survey-font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', Helvetica, Arial, sans-serif;\n+ --ph-survey-border-color: #e5e7eb;\n+ --ph-survey-border-radius: 8px;\n+ --ph-survey-card-border-radius: 16px;\n+ --ph-survey-body-background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n+ --ph-survey-header-background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n+ --ph-survey-header-text-color: white;\n+ --ph-survey-background-color: #ffffff;\n+ --ph-survey-text-primary-color: #111827;\n+ --ph-survey-text-subtle-color: #6b7280;\n+ --ph-survey-input-background: #ffffff;\n+ --ph-survey-submit-button-color: #2563eb;\n+ --ph-survey-submit-button-text-color: white;\n+ --ph-survey-rating-button-color: #f8fafc;\n+ --ph-survey-rating-active-bg-color: #2563eb;\n+ --ph-survey-rating-button-text-color: #374151;\n+ --ph-survey-rating-button-active-text-color: white;\n+ --ph-survey-disabled-button-opacity: 0.6;\n+ --ph-survey-focus-ring: 0 0 0 3px rgba(37, 99, 235, 0.1);\n+ --ph-survey-box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);\n+ }\n+\n+ * {\n+ box-sizing: border-box;\n+ }\n+\n+ /* Base Layout */\n+ body {\n+ font-family: var(--ph-survey-font-family);\n+ margin: 0;\n+ padding: 0;\n+ background: var(--ph-survey-body-background);\n+ min-height: 100vh;\n+ line-height: 1.6;\n+ color: var(--ph-survey-text-primary-color);\n+ font-size: 16px;\n+ -webkit-font-smoothing: antialiased;\n+ }\n+\n+ .main-container {\n+ min-height: 100vh;\n+ display: flex;\n+ align-items: center;\n+ justify-content: center;\n+ padding: 1rem;\n+ box-sizing: border-box;\n+ }\n+\n+ .survey-card {\n+ background: white;\n+ border-radius: var(--ph-survey-card-border-radius);\n+ box-shadow: var(--ph-survey-box-shadow);\n+ max-width: 720px;\n+ width: 100%;\n+ overflow: hidden;\n+ max-height: 90vh;\n+ display: flex;\n+ flex-direction: column;\n+ animation: slideUp 0.6s ease-out;\n+ }\n+\n+ /* Survey Header */\n+ .survey-header {\n+ background: var(--ph-survey-header-background);\n+ color: var(--ph-survey-header-text-color);\n+ padding: 1.75rem 2rem 1.5rem;\n+ text-align: center;\n+ flex-shrink: 0;\n+ }\n+\n+ .survey-title {\n+ font-size: 1.75rem;\n+ font-weight: 700;\n+ margin: 0;\n+ }\n+\n+ .survey-description {\n+ font-size: 1rem;\n+ margin: 0;\n+ opacity: 0.9;\n+ line-height: 1.4;\n+ }\n+\n+ /* Survey Content */\n+ .survey-content {\n+ flex: 1;\n+ display: flex;\n+ flex-direction: column;\n+ min-height: 0;\n+ }\n+\n+ .survey-box {\n+ display: flex;\n+ flex-direction: column;\n+ gap: 1rem;\n+ flex: 1;\n+ min-height: 0;\n+ }\n+\n+ .bottom-section {\n+ display: flex;\n+ flex-direction: column;\n+ gap: 0.75rem;\n+ }\n+\n+ .survey-form,\n+ .thank-you-message {\n+ width: 100%;\n+ margin: 0;\n+ border: none;\n+ border-radius: 0;\n+ box-shadow: none;\n+ background: white;\n+ padding: 1.5rem 2rem;\n+ display: flex;\n+ flex-direction: column;\n+ justify-content: center;\n+ min-height: 0;\n+ }\n+\n+ /* Question Styling */\n+ .survey-question {\n+ font-size: 1.25rem;\n+ font-weight: 600;\n+ color: var(--ph-survey-text-primary-color);\n+ line-height: 1.4;\n+ margin: 0;\n+ }\n+\n+ .survey-question-description {\n+ font-size: 1rem;\n+ color: var(--ph-survey-text-subtle-color);\n+ margin-top: 0.25rem;\n+ margin-bottom: 1.25rem;\n+ }\n+\n+ .question-container,\n+ .thank-you-message {\n+ display: flex;\n+ flex-direction: column;\n+ justify-content: center;\n+ gap: 8px;\n+ }\n+\n+ .response-choice {\n+ display: flex;\n+ gap: 8px;\n+ align-items: center;\n+ }\n+\n+\n+ /* Input Styling */\n+ textarea,\n+ input[type='text'] {\n+ border: 2px solid var(--ph-survey-border-color);\n+ border-radius: var(--ph-survey-border-radius);\n+ padding: 1rem;\n+ font-size: 1rem;\n+ line-height: 1.5;\n+ transition: all 0.2s ease;\n+ background: var(--ph-survey-input-background);\n+ color: var(--ph-survey-text-primary-color);\n+ width: 100%;\n+ font-family: var(--ph-survey-font-family);\n+ }\n+\n+ textarea:focus,\n+ input[type='text']:focus {\n+ outline: none;\n+ border-color: var(--ph-survey-rating-active-bg-color);\n+ box-shadow: var(--ph-survey-focus-ring);\n+ }\n+\n+ textarea:hover:not(:focus),\n+ input[type='text']:hover:not(:focus) {\n+ border-color: var(--ph-survey-rating-active-bg-color);\n+ }\n+\n+ /* Multiple Choice Options */\n+ .multiple-choice-options {\n+ display: flex;\n+ flex-direction: column;\n+ gap: 0.625rem;\n+ flex: 1;\n+ justify-content: flex-start;\n+ overflow-y: auto;\n+ max-height: 400px;\n+ padding-right: 0.5rem;\n+ margin: 0;\n+ padding-left: 0;\n+ border: none;\n+ }\n+\n+ /* Fieldset styling */\n+ fieldset {\n+ border: none;\n+ margin: 0;\n+ padding: 0;\n+ }\n+\n+ .multiple-choice-options label {\n+ border: 2px solid var(--ph-survey-border-color);\n+ border-radius: var(--ph-survey-border-radius);\n+ padding: 0.875rem 1.25rem;\n+ cursor: pointer;\n+ transition: all 0.2s ease;\n+ background: white;\n+ font-size: 1rem;\n+ min-height: 56px;\n+ display: flex;\n+ align-items: center;\n+ gap: 12px;\n+ flex-shrink: 0;\n+ color: var(--ph-survey-text-primary-color);\n+ font-family: var(--ph-survey-font-family);\n+ }\n+\n+ .choice-option-open {\n+ flex-wrap: wrap;\n+ }\n+\n+ .multiple-choice-options label:hover:not(:has(input:checked)) {\n+ border-color: #d1d5db;\n+ background: #f9fafb;\n+ }\n+\n+ .multiple-choice-options label:has(input:checked) {\n+ border-color: var(--ph-survey-rating-active-bg-color);\n+ background: #eff6ff;\n+ }\n+\n+ .multiple-choice-options input[type='checkbox'],\n+ .multiple-choice-options input[type='radio'] {\n+ appearance: none;\n+ width: 1rem;\n+ height: 1rem;\n+ background: var(--ph-survey-input-background);\n+ border: 1.5px solid var(--ph-survey-border-color);\n+ cursor: pointer;\n+ border-radius: 3px;\n+ flex-shrink: 0;\n+ transition: all 0.2s ease;\n+ position: relative;\n+ margin: 0;\n+ }\n+\n+ .multiple-choice-options input[type='radio'] {\n+ border-radius: 50%;\n+ }\n+\n+ .multiple-choice-options input[type='checkbox']:hover,\n+ .multiple-choice-options input[type='radio']:hover {\n+ border-color: var(--ph-survey-rating-active-bg-color);\n+ transform: scale(1.05);\n+ }\n+\n+ .multiple-choice-options input[type='checkbox']:checked,\n+ .multiple-choice-options input[type='radio']:checked {\n+ background: var(--ph-survey-rating-active-bg-color);\n+ border-color: var(--ph-survey-rating-active-bg-color);\n+ }\n+\n+ .multiple-choice-options input[type='checkbox']:checked::after {\n+ content: '';\n+ position: absolute;\n+ left: 4px;\n+ width: 4px;\n+ height: 8px;\n+ border: solid white;\n+ border-width: 0 2px 2px 0;\n+ transform: rotate(45deg);\n+ }\n+\n+ .multiple-choice-options input[type='radio']:checked::after {\n+ content: '';\n+ position: absolute;\n+ left: 3.5px;\n+ top: 3.5px;\n+ width: 6px;\n+ height: 6px;\n+ border-radius: 50%;\n+ background: white;\n+ }\n+\n+ /* Rating Styles */\n+ .rating-text {\n+ display: flex;\n+ flex-direction: row;\n+ font-size: 0.8rem;\n+ justify-content: space-between;\n+ opacity: 0.7;\n+ }\n+\n+ .rating-options-number {\n+ display: grid;\n+ grid-auto-columns: 1fr;\n+ grid-auto-flow: column;\n+ border-radius: var(--ph-survey-border-radius);\n+ overflow: hidden;\n+ border: 2px solid var(--ph-survey-border-color);\n+ }\n+\n+ .ratings-number {\n+ padding: 0.875rem 0;\n+ border: none;\n+ background-color: var(--ph-survey-rating-button-color);\n+ border-right: 1px solid var(--ph-survey-border-color);\n+ text-align: center;\n+ cursor: pointer;\n+ color: var(--ph-survey-rating-button-text-color);\n+ font-weight: 600;\n+ transition: all 0.2s ease;\n+ font-family: var(--ph-survey-font-family);\n+ }\n+\n+ .ratings-number:last-of-type {\n+ border-right: 0;\n+ }\n+\n+ .ratings-number:hover {\n+ filter: brightness(0.95);\n+ }\n+\n+ .ratings-number.rating-active {\n+ background: var(--ph-survey-rating-active-bg-color);\n+ color: var(--ph-survey-rating-button-active-text-color);\n+ }\n+\n+ /* Button Styling */\n+ .form-submit {\n+ background: var(--ph-survey-submit-button-color);\n+ border: none;\n+ border-radius: var(--ph-survey-border-radius);\n+ padding: 0.875rem 2rem;\n+ font-size: 1rem;\n+ font-weight: 600;\n+ color: var(--ph-survey-submit-button-text-color);\n+ cursor: pointer;\n+ transition: all 0.2s ease;\n+ width: 100%;\n+ margin-top: 1rem;\n+ font-family: var(--ph-survey-font-family);\n+ }\n+\n+ .form-submit:hover:not([disabled]) {\n+ filter: brightness(0.9);\n+ transform: translateY(-1px);\n+ box-shadow: 0 4px 12px rgba(37, 99, 235, 0.3);\n+ }\n+\n+ .form-submit:active:not([disabled]) {\n+ transform: translateY(0);\n+ }\n+\n+ .form-submit[disabled] {\n+ opacity: var(--ph-survey-disabled-button-opacity);\n+ cursor: not-allowed;\n+ }\n+\n+ /* Footer Branding */\n+ .footer-branding {\n+ font-size: 11px;\n+ font-weight: 500;\n+ display: flex;\n+ justify-content: center;\n+ gap: 4px;\n+ align-items: center;\n+ text-decoration: none;\n+ opacity: 0.6;\n+ transition: all 0.2s ease;\n+ color: var(--ph-survey-text-subtle-color);\n+ font-family: var(--ph-survey-font-family);\n+ }\n+\n+ .footer-branding:hover {\n+ opacity: 1;\n+ }\n+\n+ .footer-branding a {\n+ text-decoration: none;\n+ color: inherit;\n+ }\n+\n+ /* Thank You Message */\n+ .thank-you-message {\n+ text-align: center;\n+ padding: 2rem;\n+ }\n+\n+ .thank-you-message-header {\n+ font-size: 1.5rem;\n+ font-weight: 700;\n+ color: var(--ph-survey-text-primary-color);\n+ margin: 0 0 1rem 0;\n+ }\n+\n+ .thank-you-message-body {\n+ font-size: 1rem;\n+ color: var(--ph-survey-text-subtle-color);\n+ opacity: 0.8;\n+ }\n+\n+ /* Scrollbar Styling */\n+ .multiple-choice-options::-webkit-scrollbar {\n+ width: 6px;\n+ }\n+\n+ .multiple-choice-options::-webkit-scrollbar-track {\n+ background: #f1f5f9;\n+ border-radius: 3px;\n+ }\n+\n+ .multiple-choice-options::-webkit-scrollbar-thumb {\n+ background: #cbd5e1;\n+ border-radius: 3px;\n+ }\n+\n+ .multiple-choice-options::-webkit-scrollbar-thumb:hover {\n+ background: #94a3b8;\n+ }\n+\n+ /* Loading State */\n+ .loading {\n+ text-align: center;\n+ padding: 3rem 2rem;\n+ color: var(--ph-survey-text-subtle-color);\n+ display: flex;\n+ flex-direction: column;\n+ align-items: center;\n+ justify-content: center;\n+ flex: 1;\n+ }\n+\n+ .loading-spinner {\n+ display: inline-block;\n+ width: 32px;\n+ height: 32px;\n+ border: 3px solid #e5e7eb;\n+ border-top: 3px solid var(--ph-survey-rating-active-bg-color);\n+ border-radius: 50%;\n+ animation: spin 1s linear infinite;\n+ margin-bottom: 1rem;\n+ }\n+\n+ .loading-text {\n+ font-size: 1.125rem;\n+ font-weight: 500;\n+ }\n+\n+ /* Hide loading when survey is rendered */\n+ #posthog-survey-container:has(.ph-survey) .loading {\n+ display: none;\n+ }\n+\n+ /* Animations */\n+ @keyframes spin {\n+ 0% {\n+ transform: rotate(0deg);\n+ }\n+\n+ 100% {\n+ transform: rotate(360deg);\n+ }\n+ }\n+\n+ @keyframes slideUp {\n+ from {\n+ opacity: 0;\n+ transform: translateY(30px);\n+ }\n+\n+ to {\n+ opacity: 1;\n+ transform: translateY(0);\n+ }\n+ }\n+\n+ /* Responsive Design */\n+ @media (max-width: 768px) {\n+ .main-container {\n+ padding: 0.5rem;\n+ }\n+\n+ .survey-header {\n+ padding: 1.5rem 1.5rem 1.25rem;\n+ }\n+\n+ .survey-title {\n+ font-size: 1.5rem;\n+ }\n+\n+ .survey-description {\n+ font-size: 0.9rem;\n+ }\n+\n+ .survey-form,\n+ .thank-you-message {\n+ padding: 1.25rem 1.5rem;\n+ }\n+\n+ .multiple-choice-options {\n+ max-height: 256px;\n+ }\n+ }\n+\n+ @media (max-height: 700px) {\n+ .main-container {\n+ padding: 0.75rem;\n+ }\n+\n+ .survey-header {\n+ padding: 1.25rem 2rem 1rem;\n+ }\n+\n+ .survey-title {\n+ font-size: 1.5rem;\n+ margin-bottom: 0.25rem;\n+ }\n+\n+ .survey-description {\n+ font-size: 0.9rem;\n+ }\n+\n+ .survey-form,\n+ .thank-you-message {\n+ padding: 1.25rem 2rem;\n+ }\n+ }\n+\n+ /* Utility classes */\n+ .sr-only {\n+ position: absolute;\n+ width: 1px;\n+ height: 1px;\n+ padding: 0;\n+ margin: -1px;\n+ overflow: hidden;\n+ clip: rect(0, 0, 0, 0);\n+ white-space: nowrap;\n+ border: 0;\n+ }\n+\n+ /* Motion preferences */\n+ @media (prefers-reduced-motion: reduce) {\n+ * {\n+ animation-duration: 0.01ms !important;\n+ animation-iteration-count: 1 !important;\n+ transition-duration: 0.01ms !important;\n+ }\n+ }\n+ </style>\n+</head>\n+\n+<body>\n+ <div class=\"main-container\">\n+ <div class=\"survey-card\">\n+ <div class=\"survey-header\">\n+ <h1 class=\"survey-title\">{{ name }}</h1>\n+ </div>\n+\n+ <div class=\"survey-content\">\n+ <div id=\"posthog-survey-container\">\n+ <div class=\"loading\">\n+ <div class=\"loading-spinner\"></div>\n+ <div class=\"loading-text\">Loading survey...</div>\n+ </div>\n+ </div>\n+ </div>\n+ </div>\n+ </div>\n+\n+ <!-- PostHog JavaScript -->\n+ <script>\n+ // Project configuration from Django context\n+ window.projectConfig = {{ project_config_json | safe }};\n+ window.surveyName = \"{{ name }}\";\n+ window.surveyId = \"{{ id }}\";\n+ window.surveyAppearance = {{ appearance | safe }};\n+\n+ const BLACK_TEXT_COLOR = '#020617'\n+\n+ function hex2rgb(c) {\n+ if (c[0] === '#') {\n+ const hexColor = c.replace(/^#/, '')\n+ const r = parseInt(hexColor.slice(0, 2), 16)\n+ const g = parseInt(hexColor.slice(2, 4), 16)\n+ const b = parseInt(hexColor.slice(4, 6), 16)\n+ return 'rgb(' + r + ',' + g + ',' + b + ')'\n+ }\n+ return 'rgb(255, 255, 255)'\n+ }\n+\n+\n+ function nameToHex(name) {\n+ return {\n+ aliceblue: '#f0f8ff',\n+ antiquewhite: '#faebd7',\n+ aqua: '#00ffff',\n+ aquamarine: '#7fffd4',\n+ azure: '#f0ffff',\n+ beige: '#f5f5dc',\n+ bisque: '#ffe4c4',\n+ black: '#000000',\n+ blanchedalmond: '#ffebcd',\n+ blue: '#0000ff',\n+ blueviolet: '#8a2be2',\n+ brown: '#a52a2a',\n+ burlywood: '#deb887',\n+ cadetblue: '#5f9ea0',\n+ chartreuse: '#7fff00',\n+ chocolate: '#d2691e',\n+ coral: '#ff7f50',\n+ cornflowerblue: '#6495ed',\n+ cornsilk: '#fff8dc',\n+ crimson: '#dc143c',\n+ cyan: '#00ffff',\n+ darkblue: '#00008b',\n+ darkcyan: '#008b8b',\n+ darkgoldenrod: '#b8860b',\n+ darkgray: '#a9a9a9',\n+ darkgreen: '#006400',\n+ darkkhaki: '#bdb76b',\n+ darkmagenta: '#8b008b',\n+ darkolivegreen: '#556b2f',\n+ darkorange: '#ff8c00',\n+ darkorchid: '#9932cc',\n+ darkred: '#8b0000',\n+ darksalmon: '#e9967a',\n+ darkseagreen: '#8fbc8f',\n+ darkslateblue: '#483d8b',\n+ darkslategray: '#2f4f4f',\n+ darkturquoise: '#00ced1',\n+ darkviolet: '#9400d3',\n+ deeppink: '#ff1493',\n+ deepskyblue: '#00bfff',\n+ dimgray: '#696969',\n+ dodgerblue: '#1e90ff',\n+ firebrick: '#b22222',\n+ floralwhite: '#fffaf0',\n+ forestgreen: '#228b22',\n+ fuchsia: '#ff00ff',\n+ gainsboro: '#dcdcdc',\n+ ghostwhite: '#f8f8ff',\n+ gold: '#ffd700',\n+ goldenrod: '#daa520',\n+ gray: '#808080',\n+ green: '#008000',\n+ greenyellow: '#adff2f',\n+ honeydew: '#f0fff0',\n+ hotpink: '#ff69b4',\n+ 'indianred ': '#cd5c5c',\n+ indigo: '#4b0082',\n+ ivory: '#fffff0',\n+ khaki: '#f0e68c',\n+ lavender: '#e6e6fa',\n+ lavenderblush: '#fff0f5',\n+ lawngreen: '#7cfc00',\n+ lemonchiffon: '#fffacd',\n+ lightblue: '#add8e6',\n+ lightcoral: '#f08080',\n+ lightcyan: '#e0ffff',\n+ lightgoldenrodyellow: '#fafad2',\n+ lightgrey: '#d3d3d3',\n+ lightgreen: '#90ee90',\n+ lightpink: '#ffb6c1',\n+ lightsalmon: '#ffa07a',\n+ lightseagreen: '#20b2aa',\n+ lightskyblue: '#87cefa',\n+ lightslategray: '#778899',\n+ lightsteelblue: '#b0c4de',\n+ lightyellow: '#ffffe0',\n+ lime: '#00ff00',\n+ limegreen: '#32cd32',\n+ linen: '#faf0e6',\n+ magenta: '#ff00ff',\n+ maroon: '#800000',\n+ mediumaquamarine: '#66cdaa',\n+ mediumblue: '#0000cd',\n+ mediumorchid: '#ba55d3',\n+ mediumpurple: '#9370d8',\n+ mediumseagreen: '#3cb371',\n+ mediumslateblue: '#7b68ee',\n+ mediumspringgreen: '#00fa9a',\n+ mediumturquoise: '#48d1cc',\n+ mediumvioletred: '#c71585',\n+ midnightblue: '#191970',\n+ mintcream: '#f5fffa',\n+ mistyrose: '#ffe4e1',\n+ moccasin: '#ffe4b5',\n+ navajowhite: '#ffdead',\n+ navy: '#000080',\n+ oldlace: '#fdf5e6',\n+ olive: '#808000',\n+ olivedrab: '#6b8e23',\n+ orange: '#ffa500',\n+ orangered: '#ff4500',\n+ orchid: '#da70d6',\n+ palegoldenrod: '#eee8aa',\n+ palegreen: '#98fb98',\n+ paleturquoise: '#afeeee',\n+ palevioletred: '#d87093',\n+ papayawhip: '#ffefd5',\n+ peachpuff: '#ffdab9',\n+ peru: '#cd853f',\n+ pink: '#ffc0cb',\n+ plum: '#dda0dd',\n+ powderblue: '#b0e0e6',\n+ purple: '#800080',\n+ red: '#ff0000',\n+ rosybrown: '#bc8f8f',\n+ royalblue: '#4169e1',\n+ saddlebrown: '#8b4513',\n+ salmon: '#fa8072',\n+ sandybrown: '#f4a460',\n+ seagreen: '#2e8b57',\n+ seashell: '#fff5ee',\n+ sienna: '#a0522d',\n+ silver: '#c0c0c0',\n+ skyblue: '#87ceeb',\n+ slateblue: '#6a5acd',\n+ slategray: '#708090',\n+ snow: '#fffafa',\n+ springgreen: '#00ff7f',\n+ steelblue: '#4682b4',\n+ tan: '#d2b48c',\n+ teal: '#008080',\n+ thistle: '#d8bfd8',\n+ tomato: '#ff6347',\n+ turquoise: '#40e0d0',\n+ violet: '#ee82ee',\n+ wheat: '#f5deb3',\n+ white: '#ffffff',\n+ whitesmoke: '#f5f5f5',\n+ yellow: '#ffff00',\n+ yellowgreen: '#9acd32',\n+ }[name.toLowerCase()]\n+ }\n+\n+ function getContrastingTextColor(color) {\n+ let rgb\n+ if (color[0] === '#') {\n+ rgb = hex2rgb(color)\n+ }\n+ if (color.startsWith('rgb')) {\n+ rgb = color\n+ }\n+ // otherwise it's a color name\n+ const nameColorToHex = nameToHex(color)\n+ if (nameColorToHex) {\n+ rgb = hex2rgb(nameColorToHex)\n+ }\n+ if (!rgb) {\n+ return BLACK_TEXT_COLOR\n+ }\n+ const colorMatch = rgb.match(/^rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)(?:,\\s*(\\d+(?:\\.\\d+)?))?\\)$/)\n+ if (colorMatch) {\n+ const r = parseInt(colorMatch[1])\n+ const g = parseInt(colorMatch[2])\n+ const b = parseInt(colorMatch[3])\n+ const hsp = Math.sqrt(0.299 * (r * r) + 0.587 * (g * g) + 0.114 * (b * b))\n+ return hsp > 127.5 ? BLACK_TEXT_COLOR : 'white'\n+ }\n+ return BLACK_TEXT_COLOR\n+ }\n+\n+ function colorToRgbaWithOpacity(color, opacity = 0.25) {\n+ let rgb\n+\n+ // Handle hex colors\n+ if (color[0] === '#') {\n+ rgb = hex2rgb(color)\n+ }\n+ // Handle rgb/rgba colors\n+ else if (color.startsWith('rgb')) {\n+ rgb = color\n+ }\n+ // Handle color names\n+ else {\n+ const nameColorToHex = nameToHex(color)\n+ if (nameColorToHex) {\n+ rgb = hex2rgb(nameColorToHex)\n+ }\n+ }\n+\n+ if (!rgb) {\n+ return `rgba(255, 255, 255, ${opacity})` // fallback to white with opacity\n+ }\n+\n+ const colorMatch = rgb.match(/^rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)(?:,\\s*(\\d+(?:\\.\\d+)?))?\\)$/)\n+ if (colorMatch) {\n+ const r = parseInt(colorMatch[1])\n+ const g = parseInt(colorMatch[2])\n+ const b = parseInt(colorMatch[3])\n+ return `rgba(${r}, ${g}, ${b}, ${opacity})`\n+ }\n+\n+ return `rgba(255, 255, 255, ${opacity})` // fallback\n+ }\n+\n+\n+ // Apply survey appearance settings as CSS variables\n+ function applySurveyAppearance(appearance) {\n+ if (!appearance) return;\n+\n+ const root = document.documentElement;\n+\n+ // Apply custom appearance settings\n+ if (appearance.backgroundColor) {\n+ // Apply to body and header instead of survey container\n+ // Use 25% opacity for body background for a softer effect\n+ root.style.setProperty('--ph-survey-body-background', colorToRgbaWithOpacity(appearance.backgroundColor, 0.25));\n+ root.style.setProperty('--ph-survey-header-background', appearance.backgroundColor);\n+ root.style.setProperty('--ph-survey-header-text-color', getContrastingTextColor(appearance.backgroundColor));\n+ }\n+\n+ if (appearance.submitButtonColor) {\n+ root.style.setProperty('--ph-survey-submit-button-color', appearance.submitButtonColor);\n+ root.style.setProperty('--ph-survey-submit-button-text-color',\n+ appearance.submitButtonTextColor || getContrastingTextColor(appearance.submitButtonColor));\n+ }\n+\n+ if (appearance.ratingButtonColor) {\n+ root.style.setProperty('--ph-survey-rating-button-color', appearance.ratingButtonColor);\n+ root.style.setProperty('--ph-survey-rating-button-text-color', getContrastingTextColor(appearance.ratingButtonColor));\n+ }\n+\n+ if (appearance.ratingButtonActiveColor) {\n+ root.style.setProperty('--ph-survey-rating-active-bg-color', appearance.ratingButtonActiveColor);\n+ root.style.setProperty('--ph-survey-rating-button-active-text-color', getContrastingTextColor(appearance.ratingButtonActiveColor));\n+ }\n+\n+ if (appearance.borderColor) {\n+ root.style.setProperty('--ph-survey-border-color', appearance.borderColor);\n+ }\n+\n+ if (appearance.borderRadius) {\n+ root.style.setProperty('--ph-survey-border-radius', appearance.borderRadius);\n+ root.style.setProperty('--ph-survey-card-border-radius', appearance.borderRadius);\n+ }\n+\n+ if (appearance.inputBackground) {\n+ root.style.setProperty('--ph-survey-input-background', appearance.inputBackground);\n+ }\n+\n+ if (appearance.textSubtleColor) {\n+ root.style.setProperty('--ph-survey-text-subtle-color', appearance.textSubtleColor);\n+ }\n+\n+ if (appearance.disabledButtonOpacity) {\n+ root.style.setProperty('--ph-survey-disabled-button-opacity', appearance.disabledButtonOpacity);\n+ }\n+\n+ // Properties not suitable for external surveys (ignored):\n+ // - zIndex: not relevant for full page\n+ // - maxWidth: we manage our own layout\n+ // - position: not relevant for full page\n+ // - boxShadow: we have our own design\n+ // - boxPadding: we have our own padding\n+ // - fontFamily: we have our own font stack\n+ // - whiteLabel: not relevant for this context\n+ // - placeholder: handled by PostHog survey rendering\n+ // - shuffleQuestions: behavioral setting, not appearance\n+ // - thankYouMessageHeader/thankYouMessageDescription: handled by PostHog survey rendering\n+ // - displayThankYouMessage: handled by PostHog survey rendering\n+ }\n+\n+ // Apply survey appearance if available\n+ if (window.surveyAppearance) {\n+ applySurveyAppearance(window.surveyAppearance);\n+ }\n+\n+ // Load PostHog from CDN\n+ !function (t, e) { var o, n, p, r; e.__SV || (window.posthog = e, e._i = [], e.init = function (i, s, a) { function g(t, e) { var o = e.split(\".\"); 2 == o.length && (t = t[o[0]], e = o[1]), t[e] = function () { t.push([e].concat(Array.prototype.slice.call(arguments, 0))) } } (p = t.createElement(\"script\")).type = \"text/javascript\", p.crossOrigin = \"anonymous\", p.async = !0, p.src = s.api_host.replace(\".i.posthog.com\", \"-assets.i.posthog.com\") + \"/static/array.js\", (r = t.getElementsByTagName(\"script\")[0]).parentNode.insertBefore(p, r); var u = e; for (void 0 !== a ? u = e[a] = [] : a = \"posthog\", u.people = u.people || [], u.toString = function (t) { var e = \"posthog\"; return \"posthog\" !== a && (e += \".\" + a), t || (e += \" (stub)\"), e }, u.people.toString = function () { return u.toString(1) + \".people (stub)\" }, o = \"init Ie Ts Ms Ee Es Rs capture Ge calculateEventProperties Os register register_once register_for_session unregister unregister_for_session js getFeatureFlag getFeatureFlagPayload isFeatureEnabled reloadFeatureFlags updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures on onFeatureFlags onSurveysLoaded onSessionId getSurveys getActiveMatchingSurveys renderSurvey canRenderSurvey canRenderSurveyAsync identify setPersonProperties group resetGroups setPersonPropertiesForFlags resetPersonPropertiesForFlags setGroupPropertiesForFlags resetGroupPropertiesForFlags reset get_distinct_id getGroups get_session_id get_session_replay_url alias set_config startSessionRecording stopSessionRecording sessionRecordingStarted captureException loadToolbar get_property getSessionProperty Ds Fs createPersonProfile Ls Ps opt_in_capturing opt_out_capturing has_opted_in_capturing has_opted_out_capturing clear_opt_in_out_capturing Cs debug I As getPageViewId captureTraceFeedback captureTraceMetric\".split(\" \"), n = 0; n < o.length; n++)g(u, o[n]); e._i.push([i, s, a]) }, e.__SV = 1) }(document, window.posthog || []);\n+\n+ // Initialize PostHog with project configuration\n+ const config = {\n+ api_host: window.projectConfig.api_host,\n+ disable_surveys_automatic_display: true,\n+ debug: true,\n+ advanced_disable_toolbar_metrics: true,\n+ persistence: 'localStorage',\n+ capture_pageview: false, // Don't capture pageviews for survey pages\n+ capture_pageleave: false\n+ };\n+\n+ // Add ui_host if available (for reverse proxy setups)\n+ if (window.projectConfig.ui_host) {\n+ config.ui_host = window.projectConfig.ui_host;\n+ }\n+\n+ posthog.init(window.projectConfig.token, config);\n+ const distinctId = new URLSearchParams(window.location.search).get('distinct_id');\n+ if (distinctId) {\n+ posthog.identify(distinctId);\n+ }",
|
|
"comment_created_at": "2025-07-21T08:16:54+00:00",
|
|
"comment_author": "marandaneto",
|
|
"comment_body": "Users will need to pay for this event, which might not be expected/intentional.\r\nCan we actually just mimic the identify behaviour without capturing the identify event?\r\nwhat i mean is, the survey events should contain the 'distinctId' but we dont necessary need to capture an identify event, an idea is to init the SDK with the `bootstrap` object and the given `distinctId`",
|
|
"pr_file_module": null
|
|
},
|
|
{
|
|
"comment_id": "2218843147",
|
|
"repo_full_name": "PostHog/posthog",
|
|
"pr_number": 33948,
|
|
"pr_file": "posthog/templates/surveys/public_survey.html",
|
|
"discussion_id": "2218491245",
|
|
"commented_code": "@@ -0,0 +1,939 @@\n+<!DOCTYPE html>\n+<html lang=\"en\">\n+\n+<head>\n+ <meta charset=\"UTF-8\">\n+ <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n+ <title>{{ name }}</title>\n+ <meta name=\"description\" content=\"Take our survey: {{ name }}\">\n+ <style>\n+ /* CSS Variables */\n+ :root {\n+ --ph-survey-font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', Helvetica, Arial, sans-serif;\n+ --ph-survey-border-color: #e5e7eb;\n+ --ph-survey-border-radius: 8px;\n+ --ph-survey-card-border-radius: 16px;\n+ --ph-survey-body-background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n+ --ph-survey-header-background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n+ --ph-survey-header-text-color: white;\n+ --ph-survey-background-color: #ffffff;\n+ --ph-survey-text-primary-color: #111827;\n+ --ph-survey-text-subtle-color: #6b7280;\n+ --ph-survey-input-background: #ffffff;\n+ --ph-survey-submit-button-color: #2563eb;\n+ --ph-survey-submit-button-text-color: white;\n+ --ph-survey-rating-button-color: #f8fafc;\n+ --ph-survey-rating-active-bg-color: #2563eb;\n+ --ph-survey-rating-button-text-color: #374151;\n+ --ph-survey-rating-button-active-text-color: white;\n+ --ph-survey-disabled-button-opacity: 0.6;\n+ --ph-survey-focus-ring: 0 0 0 3px rgba(37, 99, 235, 0.1);\n+ --ph-survey-box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);\n+ }\n+\n+ * {\n+ box-sizing: border-box;\n+ }\n+\n+ /* Base Layout */\n+ body {\n+ font-family: var(--ph-survey-font-family);\n+ margin: 0;\n+ padding: 0;\n+ background: var(--ph-survey-body-background);\n+ min-height: 100vh;\n+ line-height: 1.6;\n+ color: var(--ph-survey-text-primary-color);\n+ font-size: 16px;\n+ -webkit-font-smoothing: antialiased;\n+ }\n+\n+ .main-container {\n+ min-height: 100vh;\n+ display: flex;\n+ align-items: center;\n+ justify-content: center;\n+ padding: 1rem;\n+ box-sizing: border-box;\n+ }\n+\n+ .survey-card {\n+ background: white;\n+ border-radius: var(--ph-survey-card-border-radius);\n+ box-shadow: var(--ph-survey-box-shadow);\n+ max-width: 720px;\n+ width: 100%;\n+ overflow: hidden;\n+ max-height: 90vh;\n+ display: flex;\n+ flex-direction: column;\n+ animation: slideUp 0.6s ease-out;\n+ }\n+\n+ /* Survey Header */\n+ .survey-header {\n+ background: var(--ph-survey-header-background);\n+ color: var(--ph-survey-header-text-color);\n+ padding: 1.75rem 2rem 1.5rem;\n+ text-align: center;\n+ flex-shrink: 0;\n+ }\n+\n+ .survey-title {\n+ font-size: 1.75rem;\n+ font-weight: 700;\n+ margin: 0;\n+ }\n+\n+ .survey-description {\n+ font-size: 1rem;\n+ margin: 0;\n+ opacity: 0.9;\n+ line-height: 1.4;\n+ }\n+\n+ /* Survey Content */\n+ .survey-content {\n+ flex: 1;\n+ display: flex;\n+ flex-direction: column;\n+ min-height: 0;\n+ }\n+\n+ .survey-box {\n+ display: flex;\n+ flex-direction: column;\n+ gap: 1rem;\n+ flex: 1;\n+ min-height: 0;\n+ }\n+\n+ .bottom-section {\n+ display: flex;\n+ flex-direction: column;\n+ gap: 0.75rem;\n+ }\n+\n+ .survey-form,\n+ .thank-you-message {\n+ width: 100%;\n+ margin: 0;\n+ border: none;\n+ border-radius: 0;\n+ box-shadow: none;\n+ background: white;\n+ padding: 1.5rem 2rem;\n+ display: flex;\n+ flex-direction: column;\n+ justify-content: center;\n+ min-height: 0;\n+ }\n+\n+ /* Question Styling */\n+ .survey-question {\n+ font-size: 1.25rem;\n+ font-weight: 600;\n+ color: var(--ph-survey-text-primary-color);\n+ line-height: 1.4;\n+ margin: 0;\n+ }\n+\n+ .survey-question-description {\n+ font-size: 1rem;\n+ color: var(--ph-survey-text-subtle-color);\n+ margin-top: 0.25rem;\n+ margin-bottom: 1.25rem;\n+ }\n+\n+ .question-container,\n+ .thank-you-message {\n+ display: flex;\n+ flex-direction: column;\n+ justify-content: center;\n+ gap: 8px;\n+ }\n+\n+ .response-choice {\n+ display: flex;\n+ gap: 8px;\n+ align-items: center;\n+ }\n+\n+\n+ /* Input Styling */\n+ textarea,\n+ input[type='text'] {\n+ border: 2px solid var(--ph-survey-border-color);\n+ border-radius: var(--ph-survey-border-radius);\n+ padding: 1rem;\n+ font-size: 1rem;\n+ line-height: 1.5;\n+ transition: all 0.2s ease;\n+ background: var(--ph-survey-input-background);\n+ color: var(--ph-survey-text-primary-color);\n+ width: 100%;\n+ font-family: var(--ph-survey-font-family);\n+ }\n+\n+ textarea:focus,\n+ input[type='text']:focus {\n+ outline: none;\n+ border-color: var(--ph-survey-rating-active-bg-color);\n+ box-shadow: var(--ph-survey-focus-ring);\n+ }\n+\n+ textarea:hover:not(:focus),\n+ input[type='text']:hover:not(:focus) {\n+ border-color: var(--ph-survey-rating-active-bg-color);\n+ }\n+\n+ /* Multiple Choice Options */\n+ .multiple-choice-options {\n+ display: flex;\n+ flex-direction: column;\n+ gap: 0.625rem;\n+ flex: 1;\n+ justify-content: flex-start;\n+ overflow-y: auto;\n+ max-height: 400px;\n+ padding-right: 0.5rem;\n+ margin: 0;\n+ padding-left: 0;\n+ border: none;\n+ }\n+\n+ /* Fieldset styling */\n+ fieldset {\n+ border: none;\n+ margin: 0;\n+ padding: 0;\n+ }\n+\n+ .multiple-choice-options label {\n+ border: 2px solid var(--ph-survey-border-color);\n+ border-radius: var(--ph-survey-border-radius);\n+ padding: 0.875rem 1.25rem;\n+ cursor: pointer;\n+ transition: all 0.2s ease;\n+ background: white;\n+ font-size: 1rem;\n+ min-height: 56px;\n+ display: flex;\n+ align-items: center;\n+ gap: 12px;\n+ flex-shrink: 0;\n+ color: var(--ph-survey-text-primary-color);\n+ font-family: var(--ph-survey-font-family);\n+ }\n+\n+ .choice-option-open {\n+ flex-wrap: wrap;\n+ }\n+\n+ .multiple-choice-options label:hover:not(:has(input:checked)) {\n+ border-color: #d1d5db;\n+ background: #f9fafb;\n+ }\n+\n+ .multiple-choice-options label:has(input:checked) {\n+ border-color: var(--ph-survey-rating-active-bg-color);\n+ background: #eff6ff;\n+ }\n+\n+ .multiple-choice-options input[type='checkbox'],\n+ .multiple-choice-options input[type='radio'] {\n+ appearance: none;\n+ width: 1rem;\n+ height: 1rem;\n+ background: var(--ph-survey-input-background);\n+ border: 1.5px solid var(--ph-survey-border-color);\n+ cursor: pointer;\n+ border-radius: 3px;\n+ flex-shrink: 0;\n+ transition: all 0.2s ease;\n+ position: relative;\n+ margin: 0;\n+ }\n+\n+ .multiple-choice-options input[type='radio'] {\n+ border-radius: 50%;\n+ }\n+\n+ .multiple-choice-options input[type='checkbox']:hover,\n+ .multiple-choice-options input[type='radio']:hover {\n+ border-color: var(--ph-survey-rating-active-bg-color);\n+ transform: scale(1.05);\n+ }\n+\n+ .multiple-choice-options input[type='checkbox']:checked,\n+ .multiple-choice-options input[type='radio']:checked {\n+ background: var(--ph-survey-rating-active-bg-color);\n+ border-color: var(--ph-survey-rating-active-bg-color);\n+ }\n+\n+ .multiple-choice-options input[type='checkbox']:checked::after {\n+ content: '';\n+ position: absolute;\n+ left: 4px;\n+ width: 4px;\n+ height: 8px;\n+ border: solid white;\n+ border-width: 0 2px 2px 0;\n+ transform: rotate(45deg);\n+ }\n+\n+ .multiple-choice-options input[type='radio']:checked::after {\n+ content: '';\n+ position: absolute;\n+ left: 3.5px;\n+ top: 3.5px;\n+ width: 6px;\n+ height: 6px;\n+ border-radius: 50%;\n+ background: white;\n+ }\n+\n+ /* Rating Styles */\n+ .rating-text {\n+ display: flex;\n+ flex-direction: row;\n+ font-size: 0.8rem;\n+ justify-content: space-between;\n+ opacity: 0.7;\n+ }\n+\n+ .rating-options-number {\n+ display: grid;\n+ grid-auto-columns: 1fr;\n+ grid-auto-flow: column;\n+ border-radius: var(--ph-survey-border-radius);\n+ overflow: hidden;\n+ border: 2px solid var(--ph-survey-border-color);\n+ }\n+\n+ .ratings-number {\n+ padding: 0.875rem 0;\n+ border: none;\n+ background-color: var(--ph-survey-rating-button-color);\n+ border-right: 1px solid var(--ph-survey-border-color);\n+ text-align: center;\n+ cursor: pointer;\n+ color: var(--ph-survey-rating-button-text-color);\n+ font-weight: 600;\n+ transition: all 0.2s ease;\n+ font-family: var(--ph-survey-font-family);\n+ }\n+\n+ .ratings-number:last-of-type {\n+ border-right: 0;\n+ }\n+\n+ .ratings-number:hover {\n+ filter: brightness(0.95);\n+ }\n+\n+ .ratings-number.rating-active {\n+ background: var(--ph-survey-rating-active-bg-color);\n+ color: var(--ph-survey-rating-button-active-text-color);\n+ }\n+\n+ /* Button Styling */\n+ .form-submit {\n+ background: var(--ph-survey-submit-button-color);\n+ border: none;\n+ border-radius: var(--ph-survey-border-radius);\n+ padding: 0.875rem 2rem;\n+ font-size: 1rem;\n+ font-weight: 600;\n+ color: var(--ph-survey-submit-button-text-color);\n+ cursor: pointer;\n+ transition: all 0.2s ease;\n+ width: 100%;\n+ margin-top: 1rem;\n+ font-family: var(--ph-survey-font-family);\n+ }\n+\n+ .form-submit:hover:not([disabled]) {\n+ filter: brightness(0.9);\n+ transform: translateY(-1px);\n+ box-shadow: 0 4px 12px rgba(37, 99, 235, 0.3);\n+ }\n+\n+ .form-submit:active:not([disabled]) {\n+ transform: translateY(0);\n+ }\n+\n+ .form-submit[disabled] {\n+ opacity: var(--ph-survey-disabled-button-opacity);\n+ cursor: not-allowed;\n+ }\n+\n+ /* Footer Branding */\n+ .footer-branding {\n+ font-size: 11px;\n+ font-weight: 500;\n+ display: flex;\n+ justify-content: center;\n+ gap: 4px;\n+ align-items: center;\n+ text-decoration: none;\n+ opacity: 0.6;\n+ transition: all 0.2s ease;\n+ color: var(--ph-survey-text-subtle-color);\n+ font-family: var(--ph-survey-font-family);\n+ }\n+\n+ .footer-branding:hover {\n+ opacity: 1;\n+ }\n+\n+ .footer-branding a {\n+ text-decoration: none;\n+ color: inherit;\n+ }\n+\n+ /* Thank You Message */\n+ .thank-you-message {\n+ text-align: center;\n+ padding: 2rem;\n+ }\n+\n+ .thank-you-message-header {\n+ font-size: 1.5rem;\n+ font-weight: 700;\n+ color: var(--ph-survey-text-primary-color);\n+ margin: 0 0 1rem 0;\n+ }\n+\n+ .thank-you-message-body {\n+ font-size: 1rem;\n+ color: var(--ph-survey-text-subtle-color);\n+ opacity: 0.8;\n+ }\n+\n+ /* Scrollbar Styling */\n+ .multiple-choice-options::-webkit-scrollbar {\n+ width: 6px;\n+ }\n+\n+ .multiple-choice-options::-webkit-scrollbar-track {\n+ background: #f1f5f9;\n+ border-radius: 3px;\n+ }\n+\n+ .multiple-choice-options::-webkit-scrollbar-thumb {\n+ background: #cbd5e1;\n+ border-radius: 3px;\n+ }\n+\n+ .multiple-choice-options::-webkit-scrollbar-thumb:hover {\n+ background: #94a3b8;\n+ }\n+\n+ /* Loading State */\n+ .loading {\n+ text-align: center;\n+ padding: 3rem 2rem;\n+ color: var(--ph-survey-text-subtle-color);\n+ display: flex;\n+ flex-direction: column;\n+ align-items: center;\n+ justify-content: center;\n+ flex: 1;\n+ }\n+\n+ .loading-spinner {\n+ display: inline-block;\n+ width: 32px;\n+ height: 32px;\n+ border: 3px solid #e5e7eb;\n+ border-top: 3px solid var(--ph-survey-rating-active-bg-color);\n+ border-radius: 50%;\n+ animation: spin 1s linear infinite;\n+ margin-bottom: 1rem;\n+ }\n+\n+ .loading-text {\n+ font-size: 1.125rem;\n+ font-weight: 500;\n+ }\n+\n+ /* Hide loading when survey is rendered */\n+ #posthog-survey-container:has(.ph-survey) .loading {\n+ display: none;\n+ }\n+\n+ /* Animations */\n+ @keyframes spin {\n+ 0% {\n+ transform: rotate(0deg);\n+ }\n+\n+ 100% {\n+ transform: rotate(360deg);\n+ }\n+ }\n+\n+ @keyframes slideUp {\n+ from {\n+ opacity: 0;\n+ transform: translateY(30px);\n+ }\n+\n+ to {\n+ opacity: 1;\n+ transform: translateY(0);\n+ }\n+ }\n+\n+ /* Responsive Design */\n+ @media (max-width: 768px) {\n+ .main-container {\n+ padding: 0.5rem;\n+ }\n+\n+ .survey-header {\n+ padding: 1.5rem 1.5rem 1.25rem;\n+ }\n+\n+ .survey-title {\n+ font-size: 1.5rem;\n+ }\n+\n+ .survey-description {\n+ font-size: 0.9rem;\n+ }\n+\n+ .survey-form,\n+ .thank-you-message {\n+ padding: 1.25rem 1.5rem;\n+ }\n+\n+ .multiple-choice-options {\n+ max-height: 256px;\n+ }\n+ }\n+\n+ @media (max-height: 700px) {\n+ .main-container {\n+ padding: 0.75rem;\n+ }\n+\n+ .survey-header {\n+ padding: 1.25rem 2rem 1rem;\n+ }\n+\n+ .survey-title {\n+ font-size: 1.5rem;\n+ margin-bottom: 0.25rem;\n+ }\n+\n+ .survey-description {\n+ font-size: 0.9rem;\n+ }\n+\n+ .survey-form,\n+ .thank-you-message {\n+ padding: 1.25rem 2rem;\n+ }\n+ }\n+\n+ /* Utility classes */\n+ .sr-only {\n+ position: absolute;\n+ width: 1px;\n+ height: 1px;\n+ padding: 0;\n+ margin: -1px;\n+ overflow: hidden;\n+ clip: rect(0, 0, 0, 0);\n+ white-space: nowrap;\n+ border: 0;\n+ }\n+\n+ /* Motion preferences */\n+ @media (prefers-reduced-motion: reduce) {\n+ * {\n+ animation-duration: 0.01ms !important;\n+ animation-iteration-count: 1 !important;\n+ transition-duration: 0.01ms !important;\n+ }\n+ }\n+ </style>\n+</head>\n+\n+<body>\n+ <div class=\"main-container\">\n+ <div class=\"survey-card\">\n+ <div class=\"survey-header\">\n+ <h1 class=\"survey-title\">{{ name }}</h1>\n+ </div>\n+\n+ <div class=\"survey-content\">\n+ <div id=\"posthog-survey-container\">\n+ <div class=\"loading\">\n+ <div class=\"loading-spinner\"></div>\n+ <div class=\"loading-text\">Loading survey...</div>\n+ </div>\n+ </div>\n+ </div>\n+ </div>\n+ </div>\n+\n+ <!-- PostHog JavaScript -->\n+ <script>\n+ // Project configuration from Django context\n+ window.projectConfig = {{ project_config_json | safe }};\n+ window.surveyName = \"{{ name }}\";\n+ window.surveyId = \"{{ id }}\";\n+ window.surveyAppearance = {{ appearance | safe }};\n+\n+ const BLACK_TEXT_COLOR = '#020617'\n+\n+ function hex2rgb(c) {\n+ if (c[0] === '#') {\n+ const hexColor = c.replace(/^#/, '')\n+ const r = parseInt(hexColor.slice(0, 2), 16)\n+ const g = parseInt(hexColor.slice(2, 4), 16)\n+ const b = parseInt(hexColor.slice(4, 6), 16)\n+ return 'rgb(' + r + ',' + g + ',' + b + ')'\n+ }\n+ return 'rgb(255, 255, 255)'\n+ }\n+\n+\n+ function nameToHex(name) {\n+ return {\n+ aliceblue: '#f0f8ff',\n+ antiquewhite: '#faebd7',\n+ aqua: '#00ffff',\n+ aquamarine: '#7fffd4',\n+ azure: '#f0ffff',\n+ beige: '#f5f5dc',\n+ bisque: '#ffe4c4',\n+ black: '#000000',\n+ blanchedalmond: '#ffebcd',\n+ blue: '#0000ff',\n+ blueviolet: '#8a2be2',\n+ brown: '#a52a2a',\n+ burlywood: '#deb887',\n+ cadetblue: '#5f9ea0',\n+ chartreuse: '#7fff00',\n+ chocolate: '#d2691e',\n+ coral: '#ff7f50',\n+ cornflowerblue: '#6495ed',\n+ cornsilk: '#fff8dc',\n+ crimson: '#dc143c',\n+ cyan: '#00ffff',\n+ darkblue: '#00008b',\n+ darkcyan: '#008b8b',\n+ darkgoldenrod: '#b8860b',\n+ darkgray: '#a9a9a9',\n+ darkgreen: '#006400',\n+ darkkhaki: '#bdb76b',\n+ darkmagenta: '#8b008b',\n+ darkolivegreen: '#556b2f',\n+ darkorange: '#ff8c00',\n+ darkorchid: '#9932cc',\n+ darkred: '#8b0000',\n+ darksalmon: '#e9967a',\n+ darkseagreen: '#8fbc8f',\n+ darkslateblue: '#483d8b',\n+ darkslategray: '#2f4f4f',\n+ darkturquoise: '#00ced1',\n+ darkviolet: '#9400d3',\n+ deeppink: '#ff1493',\n+ deepskyblue: '#00bfff',\n+ dimgray: '#696969',\n+ dodgerblue: '#1e90ff',\n+ firebrick: '#b22222',\n+ floralwhite: '#fffaf0',\n+ forestgreen: '#228b22',\n+ fuchsia: '#ff00ff',\n+ gainsboro: '#dcdcdc',\n+ ghostwhite: '#f8f8ff',\n+ gold: '#ffd700',\n+ goldenrod: '#daa520',\n+ gray: '#808080',\n+ green: '#008000',\n+ greenyellow: '#adff2f',\n+ honeydew: '#f0fff0',\n+ hotpink: '#ff69b4',\n+ 'indianred ': '#cd5c5c',\n+ indigo: '#4b0082',\n+ ivory: '#fffff0',\n+ khaki: '#f0e68c',\n+ lavender: '#e6e6fa',\n+ lavenderblush: '#fff0f5',\n+ lawngreen: '#7cfc00',\n+ lemonchiffon: '#fffacd',\n+ lightblue: '#add8e6',\n+ lightcoral: '#f08080',\n+ lightcyan: '#e0ffff',\n+ lightgoldenrodyellow: '#fafad2',\n+ lightgrey: '#d3d3d3',\n+ lightgreen: '#90ee90',\n+ lightpink: '#ffb6c1',\n+ lightsalmon: '#ffa07a',\n+ lightseagreen: '#20b2aa',\n+ lightskyblue: '#87cefa',\n+ lightslategray: '#778899',\n+ lightsteelblue: '#b0c4de',\n+ lightyellow: '#ffffe0',\n+ lime: '#00ff00',\n+ limegreen: '#32cd32',\n+ linen: '#faf0e6',\n+ magenta: '#ff00ff',\n+ maroon: '#800000',\n+ mediumaquamarine: '#66cdaa',\n+ mediumblue: '#0000cd',\n+ mediumorchid: '#ba55d3',\n+ mediumpurple: '#9370d8',\n+ mediumseagreen: '#3cb371',\n+ mediumslateblue: '#7b68ee',\n+ mediumspringgreen: '#00fa9a',\n+ mediumturquoise: '#48d1cc',\n+ mediumvioletred: '#c71585',\n+ midnightblue: '#191970',\n+ mintcream: '#f5fffa',\n+ mistyrose: '#ffe4e1',\n+ moccasin: '#ffe4b5',\n+ navajowhite: '#ffdead',\n+ navy: '#000080',\n+ oldlace: '#fdf5e6',\n+ olive: '#808000',\n+ olivedrab: '#6b8e23',\n+ orange: '#ffa500',\n+ orangered: '#ff4500',\n+ orchid: '#da70d6',\n+ palegoldenrod: '#eee8aa',\n+ palegreen: '#98fb98',\n+ paleturquoise: '#afeeee',\n+ palevioletred: '#d87093',\n+ papayawhip: '#ffefd5',\n+ peachpuff: '#ffdab9',\n+ peru: '#cd853f',\n+ pink: '#ffc0cb',\n+ plum: '#dda0dd',\n+ powderblue: '#b0e0e6',\n+ purple: '#800080',\n+ red: '#ff0000',\n+ rosybrown: '#bc8f8f',\n+ royalblue: '#4169e1',\n+ saddlebrown: '#8b4513',\n+ salmon: '#fa8072',\n+ sandybrown: '#f4a460',\n+ seagreen: '#2e8b57',\n+ seashell: '#fff5ee',\n+ sienna: '#a0522d',\n+ silver: '#c0c0c0',\n+ skyblue: '#87ceeb',\n+ slateblue: '#6a5acd',\n+ slategray: '#708090',\n+ snow: '#fffafa',\n+ springgreen: '#00ff7f',\n+ steelblue: '#4682b4',\n+ tan: '#d2b48c',\n+ teal: '#008080',\n+ thistle: '#d8bfd8',\n+ tomato: '#ff6347',\n+ turquoise: '#40e0d0',\n+ violet: '#ee82ee',\n+ wheat: '#f5deb3',\n+ white: '#ffffff',\n+ whitesmoke: '#f5f5f5',\n+ yellow: '#ffff00',\n+ yellowgreen: '#9acd32',\n+ }[name.toLowerCase()]\n+ }\n+\n+ function getContrastingTextColor(color) {\n+ let rgb\n+ if (color[0] === '#') {\n+ rgb = hex2rgb(color)\n+ }\n+ if (color.startsWith('rgb')) {\n+ rgb = color\n+ }\n+ // otherwise it's a color name\n+ const nameColorToHex = nameToHex(color)\n+ if (nameColorToHex) {\n+ rgb = hex2rgb(nameColorToHex)\n+ }\n+ if (!rgb) {\n+ return BLACK_TEXT_COLOR\n+ }\n+ const colorMatch = rgb.match(/^rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)(?:,\\s*(\\d+(?:\\.\\d+)?))?\\)$/)\n+ if (colorMatch) {\n+ const r = parseInt(colorMatch[1])\n+ const g = parseInt(colorMatch[2])\n+ const b = parseInt(colorMatch[3])\n+ const hsp = Math.sqrt(0.299 * (r * r) + 0.587 * (g * g) + 0.114 * (b * b))\n+ return hsp > 127.5 ? BLACK_TEXT_COLOR : 'white'\n+ }\n+ return BLACK_TEXT_COLOR\n+ }\n+\n+ function colorToRgbaWithOpacity(color, opacity = 0.25) {\n+ let rgb\n+\n+ // Handle hex colors\n+ if (color[0] === '#') {\n+ rgb = hex2rgb(color)\n+ }\n+ // Handle rgb/rgba colors\n+ else if (color.startsWith('rgb')) {\n+ rgb = color\n+ }\n+ // Handle color names\n+ else {\n+ const nameColorToHex = nameToHex(color)\n+ if (nameColorToHex) {\n+ rgb = hex2rgb(nameColorToHex)\n+ }\n+ }\n+\n+ if (!rgb) {\n+ return `rgba(255, 255, 255, ${opacity})` // fallback to white with opacity\n+ }\n+\n+ const colorMatch = rgb.match(/^rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)(?:,\\s*(\\d+(?:\\.\\d+)?))?\\)$/)\n+ if (colorMatch) {\n+ const r = parseInt(colorMatch[1])\n+ const g = parseInt(colorMatch[2])\n+ const b = parseInt(colorMatch[3])\n+ return `rgba(${r}, ${g}, ${b}, ${opacity})`\n+ }\n+\n+ return `rgba(255, 255, 255, ${opacity})` // fallback\n+ }\n+\n+\n+ // Apply survey appearance settings as CSS variables\n+ function applySurveyAppearance(appearance) {\n+ if (!appearance) return;\n+\n+ const root = document.documentElement;\n+\n+ // Apply custom appearance settings\n+ if (appearance.backgroundColor) {\n+ // Apply to body and header instead of survey container\n+ // Use 25% opacity for body background for a softer effect\n+ root.style.setProperty('--ph-survey-body-background', colorToRgbaWithOpacity(appearance.backgroundColor, 0.25));\n+ root.style.setProperty('--ph-survey-header-background', appearance.backgroundColor);\n+ root.style.setProperty('--ph-survey-header-text-color', getContrastingTextColor(appearance.backgroundColor));\n+ }\n+\n+ if (appearance.submitButtonColor) {\n+ root.style.setProperty('--ph-survey-submit-button-color', appearance.submitButtonColor);\n+ root.style.setProperty('--ph-survey-submit-button-text-color',\n+ appearance.submitButtonTextColor || getContrastingTextColor(appearance.submitButtonColor));\n+ }\n+\n+ if (appearance.ratingButtonColor) {\n+ root.style.setProperty('--ph-survey-rating-button-color', appearance.ratingButtonColor);\n+ root.style.setProperty('--ph-survey-rating-button-text-color', getContrastingTextColor(appearance.ratingButtonColor));\n+ }\n+\n+ if (appearance.ratingButtonActiveColor) {\n+ root.style.setProperty('--ph-survey-rating-active-bg-color', appearance.ratingButtonActiveColor);\n+ root.style.setProperty('--ph-survey-rating-button-active-text-color', getContrastingTextColor(appearance.ratingButtonActiveColor));\n+ }\n+\n+ if (appearance.borderColor) {\n+ root.style.setProperty('--ph-survey-border-color', appearance.borderColor);\n+ }\n+\n+ if (appearance.borderRadius) {\n+ root.style.setProperty('--ph-survey-border-radius', appearance.borderRadius);\n+ root.style.setProperty('--ph-survey-card-border-radius', appearance.borderRadius);\n+ }\n+\n+ if (appearance.inputBackground) {\n+ root.style.setProperty('--ph-survey-input-background', appearance.inputBackground);\n+ }\n+\n+ if (appearance.textSubtleColor) {\n+ root.style.setProperty('--ph-survey-text-subtle-color', appearance.textSubtleColor);\n+ }\n+\n+ if (appearance.disabledButtonOpacity) {\n+ root.style.setProperty('--ph-survey-disabled-button-opacity', appearance.disabledButtonOpacity);\n+ }\n+\n+ // Properties not suitable for external surveys (ignored):\n+ // - zIndex: not relevant for full page\n+ // - maxWidth: we manage our own layout\n+ // - position: not relevant for full page\n+ // - boxShadow: we have our own design\n+ // - boxPadding: we have our own padding\n+ // - fontFamily: we have our own font stack\n+ // - whiteLabel: not relevant for this context\n+ // - placeholder: handled by PostHog survey rendering\n+ // - shuffleQuestions: behavioral setting, not appearance\n+ // - thankYouMessageHeader/thankYouMessageDescription: handled by PostHog survey rendering\n+ // - displayThankYouMessage: handled by PostHog survey rendering\n+ }\n+\n+ // Apply survey appearance if available\n+ if (window.surveyAppearance) {\n+ applySurveyAppearance(window.surveyAppearance);\n+ }\n+\n+ // Load PostHog from CDN\n+ !function (t, e) { var o, n, p, r; e.__SV || (window.posthog = e, e._i = [], e.init = function (i, s, a) { function g(t, e) { var o = e.split(\".\"); 2 == o.length && (t = t[o[0]], e = o[1]), t[e] = function () { t.push([e].concat(Array.prototype.slice.call(arguments, 0))) } } (p = t.createElement(\"script\")).type = \"text/javascript\", p.crossOrigin = \"anonymous\", p.async = !0, p.src = s.api_host.replace(\".i.posthog.com\", \"-assets.i.posthog.com\") + \"/static/array.js\", (r = t.getElementsByTagName(\"script\")[0]).parentNode.insertBefore(p, r); var u = e; for (void 0 !== a ? u = e[a] = [] : a = \"posthog\", u.people = u.people || [], u.toString = function (t) { var e = \"posthog\"; return \"posthog\" !== a && (e += \".\" + a), t || (e += \" (stub)\"), e }, u.people.toString = function () { return u.toString(1) + \".people (stub)\" }, o = \"init Ie Ts Ms Ee Es Rs capture Ge calculateEventProperties Os register register_once register_for_session unregister unregister_for_session js getFeatureFlag getFeatureFlagPayload isFeatureEnabled reloadFeatureFlags updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures on onFeatureFlags onSurveysLoaded onSessionId getSurveys getActiveMatchingSurveys renderSurvey canRenderSurvey canRenderSurveyAsync identify setPersonProperties group resetGroups setPersonPropertiesForFlags resetPersonPropertiesForFlags setGroupPropertiesForFlags resetGroupPropertiesForFlags reset get_distinct_id getGroups get_session_id get_session_replay_url alias set_config startSessionRecording stopSessionRecording sessionRecordingStarted captureException loadToolbar get_property getSessionProperty Ds Fs createPersonProfile Ls Ps opt_in_capturing opt_out_capturing has_opted_in_capturing has_opted_out_capturing clear_opt_in_out_capturing Cs debug I As getPageViewId captureTraceFeedback captureTraceMetric\".split(\" \"), n = 0; n < o.length; n++)g(u, o[n]); e._i.push([i, s, a]) }, e.__SV = 1) }(document, window.posthog || []);\n+\n+ // Initialize PostHog with project configuration\n+ const config = {\n+ api_host: window.projectConfig.api_host,\n+ disable_surveys_automatic_display: true,\n+ debug: true,\n+ advanced_disable_toolbar_metrics: true,\n+ persistence: 'localStorage',\n+ capture_pageview: false, // Don't capture pageviews for survey pages\n+ capture_pageleave: false\n+ };\n+\n+ // Add ui_host if available (for reverse proxy setups)\n+ if (window.projectConfig.ui_host) {\n+ config.ui_host = window.projectConfig.ui_host;\n+ }\n+\n+ posthog.init(window.projectConfig.token, config);\n+ const distinctId = new URLSearchParams(window.location.search).get('distinct_id');\n+ if (distinctId) {\n+ posthog.identify(distinctId);\n+ }",
|
|
"comment_created_at": "2025-07-21T10:59:14+00:00",
|
|
"comment_author": "ioannisj",
|
|
"comment_body": "\ud83d\udc4d bootstrap with distinctId make sense to me if possible",
|
|
"pr_file_module": null
|
|
},
|
|
{
|
|
"comment_id": "2220015458",
|
|
"repo_full_name": "PostHog/posthog",
|
|
"pr_number": 33948,
|
|
"pr_file": "posthog/templates/surveys/public_survey.html",
|
|
"discussion_id": "2218491245",
|
|
"commented_code": "@@ -0,0 +1,939 @@\n+<!DOCTYPE html>\n+<html lang=\"en\">\n+\n+<head>\n+ <meta charset=\"UTF-8\">\n+ <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n+ <title>{{ name }}</title>\n+ <meta name=\"description\" content=\"Take our survey: {{ name }}\">\n+ <style>\n+ /* CSS Variables */\n+ :root {\n+ --ph-survey-font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', Helvetica, Arial, sans-serif;\n+ --ph-survey-border-color: #e5e7eb;\n+ --ph-survey-border-radius: 8px;\n+ --ph-survey-card-border-radius: 16px;\n+ --ph-survey-body-background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n+ --ph-survey-header-background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n+ --ph-survey-header-text-color: white;\n+ --ph-survey-background-color: #ffffff;\n+ --ph-survey-text-primary-color: #111827;\n+ --ph-survey-text-subtle-color: #6b7280;\n+ --ph-survey-input-background: #ffffff;\n+ --ph-survey-submit-button-color: #2563eb;\n+ --ph-survey-submit-button-text-color: white;\n+ --ph-survey-rating-button-color: #f8fafc;\n+ --ph-survey-rating-active-bg-color: #2563eb;\n+ --ph-survey-rating-button-text-color: #374151;\n+ --ph-survey-rating-button-active-text-color: white;\n+ --ph-survey-disabled-button-opacity: 0.6;\n+ --ph-survey-focus-ring: 0 0 0 3px rgba(37, 99, 235, 0.1);\n+ --ph-survey-box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);\n+ }\n+\n+ * {\n+ box-sizing: border-box;\n+ }\n+\n+ /* Base Layout */\n+ body {\n+ font-family: var(--ph-survey-font-family);\n+ margin: 0;\n+ padding: 0;\n+ background: var(--ph-survey-body-background);\n+ min-height: 100vh;\n+ line-height: 1.6;\n+ color: var(--ph-survey-text-primary-color);\n+ font-size: 16px;\n+ -webkit-font-smoothing: antialiased;\n+ }\n+\n+ .main-container {\n+ min-height: 100vh;\n+ display: flex;\n+ align-items: center;\n+ justify-content: center;\n+ padding: 1rem;\n+ box-sizing: border-box;\n+ }\n+\n+ .survey-card {\n+ background: white;\n+ border-radius: var(--ph-survey-card-border-radius);\n+ box-shadow: var(--ph-survey-box-shadow);\n+ max-width: 720px;\n+ width: 100%;\n+ overflow: hidden;\n+ max-height: 90vh;\n+ display: flex;\n+ flex-direction: column;\n+ animation: slideUp 0.6s ease-out;\n+ }\n+\n+ /* Survey Header */\n+ .survey-header {\n+ background: var(--ph-survey-header-background);\n+ color: var(--ph-survey-header-text-color);\n+ padding: 1.75rem 2rem 1.5rem;\n+ text-align: center;\n+ flex-shrink: 0;\n+ }\n+\n+ .survey-title {\n+ font-size: 1.75rem;\n+ font-weight: 700;\n+ margin: 0;\n+ }\n+\n+ .survey-description {\n+ font-size: 1rem;\n+ margin: 0;\n+ opacity: 0.9;\n+ line-height: 1.4;\n+ }\n+\n+ /* Survey Content */\n+ .survey-content {\n+ flex: 1;\n+ display: flex;\n+ flex-direction: column;\n+ min-height: 0;\n+ }\n+\n+ .survey-box {\n+ display: flex;\n+ flex-direction: column;\n+ gap: 1rem;\n+ flex: 1;\n+ min-height: 0;\n+ }\n+\n+ .bottom-section {\n+ display: flex;\n+ flex-direction: column;\n+ gap: 0.75rem;\n+ }\n+\n+ .survey-form,\n+ .thank-you-message {\n+ width: 100%;\n+ margin: 0;\n+ border: none;\n+ border-radius: 0;\n+ box-shadow: none;\n+ background: white;\n+ padding: 1.5rem 2rem;\n+ display: flex;\n+ flex-direction: column;\n+ justify-content: center;\n+ min-height: 0;\n+ }\n+\n+ /* Question Styling */\n+ .survey-question {\n+ font-size: 1.25rem;\n+ font-weight: 600;\n+ color: var(--ph-survey-text-primary-color);\n+ line-height: 1.4;\n+ margin: 0;\n+ }\n+\n+ .survey-question-description {\n+ font-size: 1rem;\n+ color: var(--ph-survey-text-subtle-color);\n+ margin-top: 0.25rem;\n+ margin-bottom: 1.25rem;\n+ }\n+\n+ .question-container,\n+ .thank-you-message {\n+ display: flex;\n+ flex-direction: column;\n+ justify-content: center;\n+ gap: 8px;\n+ }\n+\n+ .response-choice {\n+ display: flex;\n+ gap: 8px;\n+ align-items: center;\n+ }\n+\n+\n+ /* Input Styling */\n+ textarea,\n+ input[type='text'] {\n+ border: 2px solid var(--ph-survey-border-color);\n+ border-radius: var(--ph-survey-border-radius);\n+ padding: 1rem;\n+ font-size: 1rem;\n+ line-height: 1.5;\n+ transition: all 0.2s ease;\n+ background: var(--ph-survey-input-background);\n+ color: var(--ph-survey-text-primary-color);\n+ width: 100%;\n+ font-family: var(--ph-survey-font-family);\n+ }\n+\n+ textarea:focus,\n+ input[type='text']:focus {\n+ outline: none;\n+ border-color: var(--ph-survey-rating-active-bg-color);\n+ box-shadow: var(--ph-survey-focus-ring);\n+ }\n+\n+ textarea:hover:not(:focus),\n+ input[type='text']:hover:not(:focus) {\n+ border-color: var(--ph-survey-rating-active-bg-color);\n+ }\n+\n+ /* Multiple Choice Options */\n+ .multiple-choice-options {\n+ display: flex;\n+ flex-direction: column;\n+ gap: 0.625rem;\n+ flex: 1;\n+ justify-content: flex-start;\n+ overflow-y: auto;\n+ max-height: 400px;\n+ padding-right: 0.5rem;\n+ margin: 0;\n+ padding-left: 0;\n+ border: none;\n+ }\n+\n+ /* Fieldset styling */\n+ fieldset {\n+ border: none;\n+ margin: 0;\n+ padding: 0;\n+ }\n+\n+ .multiple-choice-options label {\n+ border: 2px solid var(--ph-survey-border-color);\n+ border-radius: var(--ph-survey-border-radius);\n+ padding: 0.875rem 1.25rem;\n+ cursor: pointer;\n+ transition: all 0.2s ease;\n+ background: white;\n+ font-size: 1rem;\n+ min-height: 56px;\n+ display: flex;\n+ align-items: center;\n+ gap: 12px;\n+ flex-shrink: 0;\n+ color: var(--ph-survey-text-primary-color);\n+ font-family: var(--ph-survey-font-family);\n+ }\n+\n+ .choice-option-open {\n+ flex-wrap: wrap;\n+ }\n+\n+ .multiple-choice-options label:hover:not(:has(input:checked)) {\n+ border-color: #d1d5db;\n+ background: #f9fafb;\n+ }\n+\n+ .multiple-choice-options label:has(input:checked) {\n+ border-color: var(--ph-survey-rating-active-bg-color);\n+ background: #eff6ff;\n+ }\n+\n+ .multiple-choice-options input[type='checkbox'],\n+ .multiple-choice-options input[type='radio'] {\n+ appearance: none;\n+ width: 1rem;\n+ height: 1rem;\n+ background: var(--ph-survey-input-background);\n+ border: 1.5px solid var(--ph-survey-border-color);\n+ cursor: pointer;\n+ border-radius: 3px;\n+ flex-shrink: 0;\n+ transition: all 0.2s ease;\n+ position: relative;\n+ margin: 0;\n+ }\n+\n+ .multiple-choice-options input[type='radio'] {\n+ border-radius: 50%;\n+ }\n+\n+ .multiple-choice-options input[type='checkbox']:hover,\n+ .multiple-choice-options input[type='radio']:hover {\n+ border-color: var(--ph-survey-rating-active-bg-color);\n+ transform: scale(1.05);\n+ }\n+\n+ .multiple-choice-options input[type='checkbox']:checked,\n+ .multiple-choice-options input[type='radio']:checked {\n+ background: var(--ph-survey-rating-active-bg-color);\n+ border-color: var(--ph-survey-rating-active-bg-color);\n+ }\n+\n+ .multiple-choice-options input[type='checkbox']:checked::after {\n+ content: '';\n+ position: absolute;\n+ left: 4px;\n+ width: 4px;\n+ height: 8px;\n+ border: solid white;\n+ border-width: 0 2px 2px 0;\n+ transform: rotate(45deg);\n+ }\n+\n+ .multiple-choice-options input[type='radio']:checked::after {\n+ content: '';\n+ position: absolute;\n+ left: 3.5px;\n+ top: 3.5px;\n+ width: 6px;\n+ height: 6px;\n+ border-radius: 50%;\n+ background: white;\n+ }\n+\n+ /* Rating Styles */\n+ .rating-text {\n+ display: flex;\n+ flex-direction: row;\n+ font-size: 0.8rem;\n+ justify-content: space-between;\n+ opacity: 0.7;\n+ }\n+\n+ .rating-options-number {\n+ display: grid;\n+ grid-auto-columns: 1fr;\n+ grid-auto-flow: column;\n+ border-radius: var(--ph-survey-border-radius);\n+ overflow: hidden;\n+ border: 2px solid var(--ph-survey-border-color);\n+ }\n+\n+ .ratings-number {\n+ padding: 0.875rem 0;\n+ border: none;\n+ background-color: var(--ph-survey-rating-button-color);\n+ border-right: 1px solid var(--ph-survey-border-color);\n+ text-align: center;\n+ cursor: pointer;\n+ color: var(--ph-survey-rating-button-text-color);\n+ font-weight: 600;\n+ transition: all 0.2s ease;\n+ font-family: var(--ph-survey-font-family);\n+ }\n+\n+ .ratings-number:last-of-type {\n+ border-right: 0;\n+ }\n+\n+ .ratings-number:hover {\n+ filter: brightness(0.95);\n+ }\n+\n+ .ratings-number.rating-active {\n+ background: var(--ph-survey-rating-active-bg-color);\n+ color: var(--ph-survey-rating-button-active-text-color);\n+ }\n+\n+ /* Button Styling */\n+ .form-submit {\n+ background: var(--ph-survey-submit-button-color);\n+ border: none;\n+ border-radius: var(--ph-survey-border-radius);\n+ padding: 0.875rem 2rem;\n+ font-size: 1rem;\n+ font-weight: 600;\n+ color: var(--ph-survey-submit-button-text-color);\n+ cursor: pointer;\n+ transition: all 0.2s ease;\n+ width: 100%;\n+ margin-top: 1rem;\n+ font-family: var(--ph-survey-font-family);\n+ }\n+\n+ .form-submit:hover:not([disabled]) {\n+ filter: brightness(0.9);\n+ transform: translateY(-1px);\n+ box-shadow: 0 4px 12px rgba(37, 99, 235, 0.3);\n+ }\n+\n+ .form-submit:active:not([disabled]) {\n+ transform: translateY(0);\n+ }\n+\n+ .form-submit[disabled] {\n+ opacity: var(--ph-survey-disabled-button-opacity);\n+ cursor: not-allowed;\n+ }\n+\n+ /* Footer Branding */\n+ .footer-branding {\n+ font-size: 11px;\n+ font-weight: 500;\n+ display: flex;\n+ justify-content: center;\n+ gap: 4px;\n+ align-items: center;\n+ text-decoration: none;\n+ opacity: 0.6;\n+ transition: all 0.2s ease;\n+ color: var(--ph-survey-text-subtle-color);\n+ font-family: var(--ph-survey-font-family);\n+ }\n+\n+ .footer-branding:hover {\n+ opacity: 1;\n+ }\n+\n+ .footer-branding a {\n+ text-decoration: none;\n+ color: inherit;\n+ }\n+\n+ /* Thank You Message */\n+ .thank-you-message {\n+ text-align: center;\n+ padding: 2rem;\n+ }\n+\n+ .thank-you-message-header {\n+ font-size: 1.5rem;\n+ font-weight: 700;\n+ color: var(--ph-survey-text-primary-color);\n+ margin: 0 0 1rem 0;\n+ }\n+\n+ .thank-you-message-body {\n+ font-size: 1rem;\n+ color: var(--ph-survey-text-subtle-color);\n+ opacity: 0.8;\n+ }\n+\n+ /* Scrollbar Styling */\n+ .multiple-choice-options::-webkit-scrollbar {\n+ width: 6px;\n+ }\n+\n+ .multiple-choice-options::-webkit-scrollbar-track {\n+ background: #f1f5f9;\n+ border-radius: 3px;\n+ }\n+\n+ .multiple-choice-options::-webkit-scrollbar-thumb {\n+ background: #cbd5e1;\n+ border-radius: 3px;\n+ }\n+\n+ .multiple-choice-options::-webkit-scrollbar-thumb:hover {\n+ background: #94a3b8;\n+ }\n+\n+ /* Loading State */\n+ .loading {\n+ text-align: center;\n+ padding: 3rem 2rem;\n+ color: var(--ph-survey-text-subtle-color);\n+ display: flex;\n+ flex-direction: column;\n+ align-items: center;\n+ justify-content: center;\n+ flex: 1;\n+ }\n+\n+ .loading-spinner {\n+ display: inline-block;\n+ width: 32px;\n+ height: 32px;\n+ border: 3px solid #e5e7eb;\n+ border-top: 3px solid var(--ph-survey-rating-active-bg-color);\n+ border-radius: 50%;\n+ animation: spin 1s linear infinite;\n+ margin-bottom: 1rem;\n+ }\n+\n+ .loading-text {\n+ font-size: 1.125rem;\n+ font-weight: 500;\n+ }\n+\n+ /* Hide loading when survey is rendered */\n+ #posthog-survey-container:has(.ph-survey) .loading {\n+ display: none;\n+ }\n+\n+ /* Animations */\n+ @keyframes spin {\n+ 0% {\n+ transform: rotate(0deg);\n+ }\n+\n+ 100% {\n+ transform: rotate(360deg);\n+ }\n+ }\n+\n+ @keyframes slideUp {\n+ from {\n+ opacity: 0;\n+ transform: translateY(30px);\n+ }\n+\n+ to {\n+ opacity: 1;\n+ transform: translateY(0);\n+ }\n+ }\n+\n+ /* Responsive Design */\n+ @media (max-width: 768px) {\n+ .main-container {\n+ padding: 0.5rem;\n+ }\n+\n+ .survey-header {\n+ padding: 1.5rem 1.5rem 1.25rem;\n+ }\n+\n+ .survey-title {\n+ font-size: 1.5rem;\n+ }\n+\n+ .survey-description {\n+ font-size: 0.9rem;\n+ }\n+\n+ .survey-form,\n+ .thank-you-message {\n+ padding: 1.25rem 1.5rem;\n+ }\n+\n+ .multiple-choice-options {\n+ max-height: 256px;\n+ }\n+ }\n+\n+ @media (max-height: 700px) {\n+ .main-container {\n+ padding: 0.75rem;\n+ }\n+\n+ .survey-header {\n+ padding: 1.25rem 2rem 1rem;\n+ }\n+\n+ .survey-title {\n+ font-size: 1.5rem;\n+ margin-bottom: 0.25rem;\n+ }\n+\n+ .survey-description {\n+ font-size: 0.9rem;\n+ }\n+\n+ .survey-form,\n+ .thank-you-message {\n+ padding: 1.25rem 2rem;\n+ }\n+ }\n+\n+ /* Utility classes */\n+ .sr-only {\n+ position: absolute;\n+ width: 1px;\n+ height: 1px;\n+ padding: 0;\n+ margin: -1px;\n+ overflow: hidden;\n+ clip: rect(0, 0, 0, 0);\n+ white-space: nowrap;\n+ border: 0;\n+ }\n+\n+ /* Motion preferences */\n+ @media (prefers-reduced-motion: reduce) {\n+ * {\n+ animation-duration: 0.01ms !important;\n+ animation-iteration-count: 1 !important;\n+ transition-duration: 0.01ms !important;\n+ }\n+ }\n+ </style>\n+</head>\n+\n+<body>\n+ <div class=\"main-container\">\n+ <div class=\"survey-card\">\n+ <div class=\"survey-header\">\n+ <h1 class=\"survey-title\">{{ name }}</h1>\n+ </div>\n+\n+ <div class=\"survey-content\">\n+ <div id=\"posthog-survey-container\">\n+ <div class=\"loading\">\n+ <div class=\"loading-spinner\"></div>\n+ <div class=\"loading-text\">Loading survey...</div>\n+ </div>\n+ </div>\n+ </div>\n+ </div>\n+ </div>\n+\n+ <!-- PostHog JavaScript -->\n+ <script>\n+ // Project configuration from Django context\n+ window.projectConfig = {{ project_config_json | safe }};\n+ window.surveyName = \"{{ name }}\";\n+ window.surveyId = \"{{ id }}\";\n+ window.surveyAppearance = {{ appearance | safe }};\n+\n+ const BLACK_TEXT_COLOR = '#020617'\n+\n+ function hex2rgb(c) {\n+ if (c[0] === '#') {\n+ const hexColor = c.replace(/^#/, '')\n+ const r = parseInt(hexColor.slice(0, 2), 16)\n+ const g = parseInt(hexColor.slice(2, 4), 16)\n+ const b = parseInt(hexColor.slice(4, 6), 16)\n+ return 'rgb(' + r + ',' + g + ',' + b + ')'\n+ }\n+ return 'rgb(255, 255, 255)'\n+ }\n+\n+\n+ function nameToHex(name) {\n+ return {\n+ aliceblue: '#f0f8ff',\n+ antiquewhite: '#faebd7',\n+ aqua: '#00ffff',\n+ aquamarine: '#7fffd4',\n+ azure: '#f0ffff',\n+ beige: '#f5f5dc',\n+ bisque: '#ffe4c4',\n+ black: '#000000',\n+ blanchedalmond: '#ffebcd',\n+ blue: '#0000ff',\n+ blueviolet: '#8a2be2',\n+ brown: '#a52a2a',\n+ burlywood: '#deb887',\n+ cadetblue: '#5f9ea0',\n+ chartreuse: '#7fff00',\n+ chocolate: '#d2691e',\n+ coral: '#ff7f50',\n+ cornflowerblue: '#6495ed',\n+ cornsilk: '#fff8dc',\n+ crimson: '#dc143c',\n+ cyan: '#00ffff',\n+ darkblue: '#00008b',\n+ darkcyan: '#008b8b',\n+ darkgoldenrod: '#b8860b',\n+ darkgray: '#a9a9a9',\n+ darkgreen: '#006400',\n+ darkkhaki: '#bdb76b',\n+ darkmagenta: '#8b008b',\n+ darkolivegreen: '#556b2f',\n+ darkorange: '#ff8c00',\n+ darkorchid: '#9932cc',\n+ darkred: '#8b0000',\n+ darksalmon: '#e9967a',\n+ darkseagreen: '#8fbc8f',\n+ darkslateblue: '#483d8b',\n+ darkslategray: '#2f4f4f',\n+ darkturquoise: '#00ced1',\n+ darkviolet: '#9400d3',\n+ deeppink: '#ff1493',\n+ deepskyblue: '#00bfff',\n+ dimgray: '#696969',\n+ dodgerblue: '#1e90ff',\n+ firebrick: '#b22222',\n+ floralwhite: '#fffaf0',\n+ forestgreen: '#228b22',\n+ fuchsia: '#ff00ff',\n+ gainsboro: '#dcdcdc',\n+ ghostwhite: '#f8f8ff',\n+ gold: '#ffd700',\n+ goldenrod: '#daa520',\n+ gray: '#808080',\n+ green: '#008000',\n+ greenyellow: '#adff2f',\n+ honeydew: '#f0fff0',\n+ hotpink: '#ff69b4',\n+ 'indianred ': '#cd5c5c',\n+ indigo: '#4b0082',\n+ ivory: '#fffff0',\n+ khaki: '#f0e68c',\n+ lavender: '#e6e6fa',\n+ lavenderblush: '#fff0f5',\n+ lawngreen: '#7cfc00',\n+ lemonchiffon: '#fffacd',\n+ lightblue: '#add8e6',\n+ lightcoral: '#f08080',\n+ lightcyan: '#e0ffff',\n+ lightgoldenrodyellow: '#fafad2',\n+ lightgrey: '#d3d3d3',\n+ lightgreen: '#90ee90',\n+ lightpink: '#ffb6c1',\n+ lightsalmon: '#ffa07a',\n+ lightseagreen: '#20b2aa',\n+ lightskyblue: '#87cefa',\n+ lightslategray: '#778899',\n+ lightsteelblue: '#b0c4de',\n+ lightyellow: '#ffffe0',\n+ lime: '#00ff00',\n+ limegreen: '#32cd32',\n+ linen: '#faf0e6',\n+ magenta: '#ff00ff',\n+ maroon: '#800000',\n+ mediumaquamarine: '#66cdaa',\n+ mediumblue: '#0000cd',\n+ mediumorchid: '#ba55d3',\n+ mediumpurple: '#9370d8',\n+ mediumseagreen: '#3cb371',\n+ mediumslateblue: '#7b68ee',\n+ mediumspringgreen: '#00fa9a',\n+ mediumturquoise: '#48d1cc',\n+ mediumvioletred: '#c71585',\n+ midnightblue: '#191970',\n+ mintcream: '#f5fffa',\n+ mistyrose: '#ffe4e1',\n+ moccasin: '#ffe4b5',\n+ navajowhite: '#ffdead',\n+ navy: '#000080',\n+ oldlace: '#fdf5e6',\n+ olive: '#808000',\n+ olivedrab: '#6b8e23',\n+ orange: '#ffa500',\n+ orangered: '#ff4500',\n+ orchid: '#da70d6',\n+ palegoldenrod: '#eee8aa',\n+ palegreen: '#98fb98',\n+ paleturquoise: '#afeeee',\n+ palevioletred: '#d87093',\n+ papayawhip: '#ffefd5',\n+ peachpuff: '#ffdab9',\n+ peru: '#cd853f',\n+ pink: '#ffc0cb',\n+ plum: '#dda0dd',\n+ powderblue: '#b0e0e6',\n+ purple: '#800080',\n+ red: '#ff0000',\n+ rosybrown: '#bc8f8f',\n+ royalblue: '#4169e1',\n+ saddlebrown: '#8b4513',\n+ salmon: '#fa8072',\n+ sandybrown: '#f4a460',\n+ seagreen: '#2e8b57',\n+ seashell: '#fff5ee',\n+ sienna: '#a0522d',\n+ silver: '#c0c0c0',\n+ skyblue: '#87ceeb',\n+ slateblue: '#6a5acd',\n+ slategray: '#708090',\n+ snow: '#fffafa',\n+ springgreen: '#00ff7f',\n+ steelblue: '#4682b4',\n+ tan: '#d2b48c',\n+ teal: '#008080',\n+ thistle: '#d8bfd8',\n+ tomato: '#ff6347',\n+ turquoise: '#40e0d0',\n+ violet: '#ee82ee',\n+ wheat: '#f5deb3',\n+ white: '#ffffff',\n+ whitesmoke: '#f5f5f5',\n+ yellow: '#ffff00',\n+ yellowgreen: '#9acd32',\n+ }[name.toLowerCase()]\n+ }\n+\n+ function getContrastingTextColor(color) {\n+ let rgb\n+ if (color[0] === '#') {\n+ rgb = hex2rgb(color)\n+ }\n+ if (color.startsWith('rgb')) {\n+ rgb = color\n+ }\n+ // otherwise it's a color name\n+ const nameColorToHex = nameToHex(color)\n+ if (nameColorToHex) {\n+ rgb = hex2rgb(nameColorToHex)\n+ }\n+ if (!rgb) {\n+ return BLACK_TEXT_COLOR\n+ }\n+ const colorMatch = rgb.match(/^rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)(?:,\\s*(\\d+(?:\\.\\d+)?))?\\)$/)\n+ if (colorMatch) {\n+ const r = parseInt(colorMatch[1])\n+ const g = parseInt(colorMatch[2])\n+ const b = parseInt(colorMatch[3])\n+ const hsp = Math.sqrt(0.299 * (r * r) + 0.587 * (g * g) + 0.114 * (b * b))\n+ return hsp > 127.5 ? BLACK_TEXT_COLOR : 'white'\n+ }\n+ return BLACK_TEXT_COLOR\n+ }\n+\n+ function colorToRgbaWithOpacity(color, opacity = 0.25) {\n+ let rgb\n+\n+ // Handle hex colors\n+ if (color[0] === '#') {\n+ rgb = hex2rgb(color)\n+ }\n+ // Handle rgb/rgba colors\n+ else if (color.startsWith('rgb')) {\n+ rgb = color\n+ }\n+ // Handle color names\n+ else {\n+ const nameColorToHex = nameToHex(color)\n+ if (nameColorToHex) {\n+ rgb = hex2rgb(nameColorToHex)\n+ }\n+ }\n+\n+ if (!rgb) {\n+ return `rgba(255, 255, 255, ${opacity})` // fallback to white with opacity\n+ }\n+\n+ const colorMatch = rgb.match(/^rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)(?:,\\s*(\\d+(?:\\.\\d+)?))?\\)$/)\n+ if (colorMatch) {\n+ const r = parseInt(colorMatch[1])\n+ const g = parseInt(colorMatch[2])\n+ const b = parseInt(colorMatch[3])\n+ return `rgba(${r}, ${g}, ${b}, ${opacity})`\n+ }\n+\n+ return `rgba(255, 255, 255, ${opacity})` // fallback\n+ }\n+\n+\n+ // Apply survey appearance settings as CSS variables\n+ function applySurveyAppearance(appearance) {\n+ if (!appearance) return;\n+\n+ const root = document.documentElement;\n+\n+ // Apply custom appearance settings\n+ if (appearance.backgroundColor) {\n+ // Apply to body and header instead of survey container\n+ // Use 25% opacity for body background for a softer effect\n+ root.style.setProperty('--ph-survey-body-background', colorToRgbaWithOpacity(appearance.backgroundColor, 0.25));\n+ root.style.setProperty('--ph-survey-header-background', appearance.backgroundColor);\n+ root.style.setProperty('--ph-survey-header-text-color', getContrastingTextColor(appearance.backgroundColor));\n+ }\n+\n+ if (appearance.submitButtonColor) {\n+ root.style.setProperty('--ph-survey-submit-button-color', appearance.submitButtonColor);\n+ root.style.setProperty('--ph-survey-submit-button-text-color',\n+ appearance.submitButtonTextColor || getContrastingTextColor(appearance.submitButtonColor));\n+ }\n+\n+ if (appearance.ratingButtonColor) {\n+ root.style.setProperty('--ph-survey-rating-button-color', appearance.ratingButtonColor);\n+ root.style.setProperty('--ph-survey-rating-button-text-color', getContrastingTextColor(appearance.ratingButtonColor));\n+ }\n+\n+ if (appearance.ratingButtonActiveColor) {\n+ root.style.setProperty('--ph-survey-rating-active-bg-color', appearance.ratingButtonActiveColor);\n+ root.style.setProperty('--ph-survey-rating-button-active-text-color', getContrastingTextColor(appearance.ratingButtonActiveColor));\n+ }\n+\n+ if (appearance.borderColor) {\n+ root.style.setProperty('--ph-survey-border-color', appearance.borderColor);\n+ }\n+\n+ if (appearance.borderRadius) {\n+ root.style.setProperty('--ph-survey-border-radius', appearance.borderRadius);\n+ root.style.setProperty('--ph-survey-card-border-radius', appearance.borderRadius);\n+ }\n+\n+ if (appearance.inputBackground) {\n+ root.style.setProperty('--ph-survey-input-background', appearance.inputBackground);\n+ }\n+\n+ if (appearance.textSubtleColor) {\n+ root.style.setProperty('--ph-survey-text-subtle-color', appearance.textSubtleColor);\n+ }\n+\n+ if (appearance.disabledButtonOpacity) {\n+ root.style.setProperty('--ph-survey-disabled-button-opacity', appearance.disabledButtonOpacity);\n+ }\n+\n+ // Properties not suitable for external surveys (ignored):\n+ // - zIndex: not relevant for full page\n+ // - maxWidth: we manage our own layout\n+ // - position: not relevant for full page\n+ // - boxShadow: we have our own design\n+ // - boxPadding: we have our own padding\n+ // - fontFamily: we have our own font stack\n+ // - whiteLabel: not relevant for this context\n+ // - placeholder: handled by PostHog survey rendering\n+ // - shuffleQuestions: behavioral setting, not appearance\n+ // - thankYouMessageHeader/thankYouMessageDescription: handled by PostHog survey rendering\n+ // - displayThankYouMessage: handled by PostHog survey rendering\n+ }\n+\n+ // Apply survey appearance if available\n+ if (window.surveyAppearance) {\n+ applySurveyAppearance(window.surveyAppearance);\n+ }\n+\n+ // Load PostHog from CDN\n+ !function (t, e) { var o, n, p, r; e.__SV || (window.posthog = e, e._i = [], e.init = function (i, s, a) { function g(t, e) { var o = e.split(\".\"); 2 == o.length && (t = t[o[0]], e = o[1]), t[e] = function () { t.push([e].concat(Array.prototype.slice.call(arguments, 0))) } } (p = t.createElement(\"script\")).type = \"text/javascript\", p.crossOrigin = \"anonymous\", p.async = !0, p.src = s.api_host.replace(\".i.posthog.com\", \"-assets.i.posthog.com\") + \"/static/array.js\", (r = t.getElementsByTagName(\"script\")[0]).parentNode.insertBefore(p, r); var u = e; for (void 0 !== a ? u = e[a] = [] : a = \"posthog\", u.people = u.people || [], u.toString = function (t) { var e = \"posthog\"; return \"posthog\" !== a && (e += \".\" + a), t || (e += \" (stub)\"), e }, u.people.toString = function () { return u.toString(1) + \".people (stub)\" }, o = \"init Ie Ts Ms Ee Es Rs capture Ge calculateEventProperties Os register register_once register_for_session unregister unregister_for_session js getFeatureFlag getFeatureFlagPayload isFeatureEnabled reloadFeatureFlags updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures on onFeatureFlags onSurveysLoaded onSessionId getSurveys getActiveMatchingSurveys renderSurvey canRenderSurvey canRenderSurveyAsync identify setPersonProperties group resetGroups setPersonPropertiesForFlags resetPersonPropertiesForFlags setGroupPropertiesForFlags resetGroupPropertiesForFlags reset get_distinct_id getGroups get_session_id get_session_replay_url alias set_config startSessionRecording stopSessionRecording sessionRecordingStarted captureException loadToolbar get_property getSessionProperty Ds Fs createPersonProfile Ls Ps opt_in_capturing opt_out_capturing has_opted_in_capturing has_opted_out_capturing clear_opt_in_out_capturing Cs debug I As getPageViewId captureTraceFeedback captureTraceMetric\".split(\" \"), n = 0; n < o.length; n++)g(u, o[n]); e._i.push([i, s, a]) }, e.__SV = 1) }(document, window.posthog || []);\n+\n+ // Initialize PostHog with project configuration\n+ const config = {\n+ api_host: window.projectConfig.api_host,\n+ disable_surveys_automatic_display: true,\n+ debug: true,\n+ advanced_disable_toolbar_metrics: true,\n+ persistence: 'localStorage',\n+ capture_pageview: false, // Don't capture pageviews for survey pages\n+ capture_pageleave: false\n+ };\n+\n+ // Add ui_host if available (for reverse proxy setups)\n+ if (window.projectConfig.ui_host) {\n+ config.ui_host = window.projectConfig.ui_host;\n+ }\n+\n+ posthog.init(window.projectConfig.token, config);\n+ const distinctId = new URLSearchParams(window.location.search).get('distinct_id');\n+ if (distinctId) {\n+ posthog.identify(distinctId);\n+ }",
|
|
"comment_created_at": "2025-07-21T19:02:56+00:00",
|
|
"comment_author": "lucasheriques",
|
|
"comment_body": "ohhh yeah, bootstrap makes much more sense. I didn't know identify also captured events. just changed it\r\n",
|
|
"pr_file_module": null
|
|
}
|
|
]
|
|
}
|
|
] |