|
| 1 | +import reflex as rx |
| 2 | + |
| 3 | +from pcweb.components.icons import get_icon |
| 4 | +from pcweb.components.button import button |
| 5 | +from typing import List |
| 6 | + |
| 7 | + |
| 8 | +# Outcomes features data |
| 9 | +OUTCOMES_FEATURES = [ |
| 10 | + { |
| 11 | + "title": "Dedicated Engineer", |
| 12 | + "description": "An expert engineer is assigned to your team to build your first app.", |
| 13 | + "icon": "backend_auth", |
| 14 | + }, |
| 15 | + { |
| 16 | + "title": "Fast Time to Launch", |
| 17 | + "description": "Get your first app up and running quickly with expert guidance.", |
| 18 | + "icon": "arrow_top_right", |
| 19 | + }, |
| 20 | + { |
| 21 | + "title": "Guaranteed Success", |
| 22 | + "description": "We ensure your app reaches a successful state before handoff.", |
| 23 | + "icon": "star", |
| 24 | + }, |
| 25 | + { |
| 26 | + "title": "Training and Enablement", |
| 27 | + "description": "Hands-on training so your team can maintain and extend your app.", |
| 28 | + "icon": "document_code", |
| 29 | + }, |
| 30 | +] |
| 31 | + |
| 32 | + |
| 33 | +def header() -> rx.Component: |
| 34 | + return rx.box( |
| 35 | + rx.el.h3( |
| 36 | + "Deliver Outcomes", |
| 37 | + class_name="text-slate-12 text-3xl font-semibold text-center", |
| 38 | + ), |
| 39 | + rx.el.p( |
| 40 | + "Your success, guaranteed. Real outcomes, real support", |
| 41 | + class_name="text-slate-9 text-xl font-semibold text-center", |
| 42 | + ), |
| 43 | + class_name="flex items-center justify-between text-slate-11 flex-col py-[5rem] 2xl:border-x border-t border-slate-4 max-w-[64.19rem] mx-auto w-full", |
| 44 | + ) |
| 45 | + |
| 46 | + |
| 47 | +def outcomes_showcase() -> rx.Component: |
| 48 | + """Central outcomes showcase component with prominent display.""" |
| 49 | + return rx.box( |
| 50 | + # Radial background |
| 51 | + rx.html( |
| 52 | + """<svg width="338" height="478" viewBox="0 0 338 478" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| 53 | +<rect x="23.824" y="210.094" width="275" height="107" rx="53.5" transform="rotate(-9 23.824 210.094)" stroke="var(--c-slate-5)"/> |
| 54 | +<rect x="8.14869" y="208.44" width="299" height="131" rx="65.5" transform="rotate(-12 8.14869 208.44)" stroke="var(--c-slate-5)"/> |
| 55 | +<rect x="-8.05511" y="208.366" width="323" height="155" rx="77.5" transform="rotate(-15 -8.05511 208.366)" stroke="var(--c-slate-5)"/> |
| 56 | +<rect x="-24.6649" y="209.92" width="347" height="179" rx="89.5" transform="rotate(-18 -24.6649 209.92)" stroke="var(--c-slate-5)"/> |
| 57 | +<rect x="-41.5532" y="213.144" width="371" height="203" rx="101.5" transform="rotate(-21 -41.5532 213.144)" stroke="var(--c-slate-5)"/> |
| 58 | +<rect x="-58.5899" y="218.069" width="395" height="227" rx="113.5" transform="rotate(-24 -58.5899 218.069)" stroke="var(--c-slate-5)"/> |
| 59 | +<rect x="-75.6415" y="224.715" width="419" height="251" rx="125.5" transform="rotate(-27 -75.6415 224.715)" stroke="var(--c-slate-5)"/> |
| 60 | +<rect x="-92.5743" y="233.097" width="443" height="275" rx="137.5" transform="rotate(-30 -92.5743 233.097)" stroke="var(--c-slate-5)"/> |
| 61 | +<rect x="-109.253" y="243.217" width="467" height="299" rx="149.5" transform="rotate(-33 -109.253 243.217)" stroke="var(--c-slate-5)"/> |
| 62 | +<rect x="-125.541" y="255.071" width="491" height="323" rx="161.5" transform="rotate(-36 -125.541 255.071)" stroke="var(--c-slate-5)"/> |
| 63 | +<rect x="-141.302" y="268.641" width="515" height="347" rx="173.5" transform="rotate(-39 -141.302 268.641)" stroke="var(--c-slate-5)"/> |
| 64 | +<rect x="-156.401" y="283.903" width="539" height="371" rx="185.5" transform="rotate(-42 -156.401 283.903)" stroke="var(--c-slate-5)"/> |
| 65 | +<rect x="-170.704" y="300.823" width="563" height="395" rx="197.5" transform="rotate(-45 -170.704 300.823)" stroke="var(--c-slate-5)"/> |
| 66 | +<rect x="-184.079" y="319.356" width="587" height="419" rx="209.5" transform="rotate(-48 -184.079 319.356)" stroke="var(--c-slate-5)"/> |
| 67 | +<rect x="-196.395" y="339.449" width="611" height="443" rx="221.5" transform="rotate(-51 -196.395 339.449)" stroke="var(--c-slate-5)"/> |
| 68 | +<rect x="-207.527" y="361.041" width="635" height="467" rx="233.5" transform="rotate(-54 -207.527 361.041)" stroke="var(--c-slate-5)"/> |
| 69 | +<rect x="-217.352" y="384.059" width="659" height="491" rx="245.5" transform="rotate(-57 -217.352 384.059)" stroke="var(--c-slate-5)"/> |
| 70 | +<rect x="-225.752" y="408.423" width="683" height="515" rx="257.5" transform="rotate(-60 -225.752 408.423)" stroke="var(--c-slate-5)"/> |
| 71 | +<rect x="-232.612" y="434.046" width="707" height="539" rx="269.5" transform="rotate(-63 -232.612 434.046)" stroke="var(--c-slate-5)"/> |
| 72 | +<rect x="-237.825" y="460.83" width="731" height="563" rx="281.5" transform="rotate(-66 -237.825 460.83)" stroke="var(--c-slate-5)"/> |
| 73 | +<rect x="-241.29" y="488.671" width="755" height="587" rx="293.5" transform="rotate(-69 -241.29 488.671)" stroke="var(--c-slate-5)"/> |
| 74 | +<rect x="-242.91" y="517.457" width="779" height="611" rx="305.5" transform="rotate(-72 -242.91 517.457)" stroke="var(--c-slate-5)"/> |
| 75 | +<rect x="-242.597" y="547.07" width="803" height="635" rx="317.5" transform="rotate(-75 -242.597 547.07)" stroke="var(--c-slate-5)"/> |
| 76 | +<rect x="-240.271" y="577.383" width="827" height="659" rx="329.5" transform="rotate(-78 -240.271 577.383)" stroke="var(--c-slate-5)"/> |
| 77 | +<rect x="-235.858" y="608.265" width="851" height="683" rx="341.5" transform="rotate(-81 -235.858 608.265)" stroke="var(--c-slate-5)"/> |
| 78 | +<rect x="-229.295" y="639.578" width="875" height="707" rx="353.5" transform="rotate(-84 -229.295 639.578)" stroke="var(--c-slate-5)"/> |
| 79 | +<rect x="-220.524" y="671.181" width="899" height="731" rx="365.5" transform="rotate(-87 -220.524 671.181)" stroke="var(--c-slate-5)"/> |
| 80 | +<rect x="-209.5" y="702.926" width="923" height="755" rx="377.5" transform="rotate(-90 -209.5 702.926)" stroke="var(--c-slate-5)"/> |
| 81 | +<rect x="-196.185" y="734.662" width="947" height="779" rx="389.5" transform="rotate(-93 -196.185 734.662)" stroke="var(--c-slate-5)"/> |
| 82 | +<rect x="-180.552" y="766.234" width="971" height="803" rx="401.5" transform="rotate(-96 -180.552 766.234)" stroke="var(--c-slate-5)"/> |
| 83 | +<rect x="-162.583" y="797.486" width="995" height="827" rx="413.5" transform="rotate(-99 -162.583 797.486)" stroke="var(--c-slate-5)"/> |
| 84 | +<rect x="-142.271" y="828.258" width="1019" height="851" rx="425.5" transform="rotate(-102 -142.271 828.258)" stroke="var(--c-slate-5)"/> |
| 85 | +<rect x="38.8498" y="213.271" width="251" height="83" rx="41.5" transform="rotate(-6 38.8498 213.271)" stroke="var(--c-slate-5)"/> |
| 86 | +<rect x="23.824" y="210.094" width="275" height="107" rx="53.5" transform="rotate(-9 23.824 210.094)" stroke="var(--c-slate-5)"/> |
| 87 | +<rect x="8.14869" y="208.44" width="299" height="131" rx="65.5" transform="rotate(-12 8.14869 208.44)" stroke="var(--c-slate-5)"/> |
| 88 | +<rect x="-8.05511" y="208.366" width="323" height="155" rx="77.5" transform="rotate(-15 -8.05511 208.366)" stroke="var(--c-slate-5)"/> |
| 89 | +<rect x="-24.6649" y="209.92" width="347" height="179" rx="89.5" transform="rotate(-18 -24.6649 209.92)" stroke="var(--c-slate-5)"/> |
| 90 | +<rect x="-41.5532" y="213.144" width="371" height="203" rx="101.5" transform="rotate(-21 -41.5532 213.144)" stroke="var(--c-slate-5)"/> |
| 91 | +<rect x="-58.5899" y="218.069" width="395" height="227" rx="113.5" transform="rotate(-24 -58.5899 218.069)" stroke="var(--c-slate-5)"/> |
| 92 | +<rect x="-75.6415" y="224.715" width="419" height="251" rx="125.5" transform="rotate(-27 -75.6415 224.715)" stroke="var(--c-slate-5)"/> |
| 93 | +<rect x="-92.5743" y="233.097" width="443" height="275" rx="137.5" transform="rotate(-30 -92.5743 233.097)" stroke="var(--c-slate-5)"/> |
| 94 | +<rect x="-109.253" y="243.217" width="467" height="299" rx="149.5" transform="rotate(-33 -109.253 243.217)" stroke="var(--c-slate-5)"/> |
| 95 | +<rect x="-125.541" y="255.071" width="491" height="323" rx="161.5" transform="rotate(-36 -125.541 255.071)" stroke="var(--c-slate-5)"/> |
| 96 | +<rect x="-141.302" y="268.641" width="515" height="347" rx="173.5" transform="rotate(-39 -141.302 268.641)" stroke="var(--c-slate-5)"/> |
| 97 | +<rect x="-156.401" y="283.903" width="539" height="371" rx="185.5" transform="rotate(-42 -156.401 283.903)" stroke="var(--c-slate-5)"/> |
| 98 | +<rect x="-170.704" y="300.823" width="563" height="395" rx="197.5" transform="rotate(-45 -170.704 300.823)" stroke="var(--c-slate-5)"/> |
| 99 | +<rect x="-184.079" y="319.356" width="587" height="419" rx="209.5" transform="rotate(-48 -184.079 319.356)" stroke="var(--c-slate-5)"/> |
| 100 | +<rect x="-196.395" y="339.449" width="611" height="443" rx="221.5" transform="rotate(-51 -196.395 339.449)" stroke="var(--c-slate-5)"/> |
| 101 | +<rect x="-207.527" y="361.041" width="635" height="467" rx="233.5" transform="rotate(-54 -207.527 361.041)" stroke="var(--c-slate-5)"/> |
| 102 | +<rect x="-217.352" y="384.059" width="659" height="491" rx="245.5" transform="rotate(-57 -217.352 384.059)" stroke="var(--c-slate-5)"/> |
| 103 | +<rect x="-225.752" y="408.423" width="683" height="515" rx="257.5" transform="rotate(-60 -225.752 408.423)" stroke="var(--c-slate-5)"/> |
| 104 | +<rect x="-232.612" y="434.046" width="707" height="539" rx="269.5" transform="rotate(-63 -232.612 434.046)" stroke="var(--c-slate-5)"/> |
| 105 | +<rect x="-237.825" y="460.83" width="731" height="563" rx="281.5" transform="rotate(-66 -237.825 460.83)" stroke="var(--c-slate-5)"/> |
| 106 | +<rect x="-241.29" y="488.671" width="755" height="587" rx="293.5" transform="rotate(-69 -241.29 488.671)" stroke="var(--c-slate-5)"/> |
| 107 | +<rect x="-242.91" y="517.457" width="779" height="611" rx="305.5" transform="rotate(-72 -242.91 517.457)" stroke="var(--c-slate-5)"/> |
| 108 | +<rect x="-242.597" y="547.07" width="803" height="635" rx="317.5" transform="rotate(-75 -242.597 547.07)" stroke="var(--c-slate-5)"/> |
| 109 | +<rect x="-240.271" y="577.383" width="827" height="659" rx="329.5" transform="rotate(-78 -240.271 577.383)" stroke="var(--c-slate-5)"/> |
| 110 | +<rect x="-235.858" y="608.265" width="851" height="683" rx="341.5" transform="rotate(-81 -235.858 608.265)" stroke="var(--c-slate-5)"/> |
| 111 | +<rect x="-229.295" y="639.578" width="875" height="707" rx="353.5" transform="rotate(-84 -229.295 639.578)" stroke="var(--c-slate-5)"/> |
| 112 | +<rect x="-220.524" y="671.181" width="899" height="731" rx="365.5" transform="rotate(-87 -220.524 671.181)" stroke="var(--c-slate-5)"/> |
| 113 | +<rect x="-209.5" y="702.926" width="923" height="755" rx="377.5" transform="rotate(-90 -209.5 702.926)" stroke="var(--c-slate-5)"/> |
| 114 | +<rect x="-196.185" y="734.662" width="947" height="779" rx="389.5" transform="rotate(-93 -196.185 734.662)" stroke="var(--c-slate-5)"/> |
| 115 | +<rect x="-180.552" y="766.234" width="971" height="803" rx="401.5" transform="rotate(-96 -180.552 766.234)" stroke="var(--c-slate-5)"/> |
| 116 | +<rect x="-162.583" y="797.486" width="995" height="827" rx="413.5" transform="rotate(-99 -162.583 797.486)" stroke="var(--c-slate-5)"/> |
| 117 | +<rect x="-142.271" y="828.258" width="1019" height="851" rx="425.5" transform="rotate(-102 -142.271 828.258)" stroke="var(--c-slate-5)"/> |
| 118 | +</svg>""", |
| 119 | + class_name="shrink-0 absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 z-[-3] pointer-events-none hidden lg:flex", |
| 120 | + ), |
| 121 | + # Gradial blur |
| 122 | + rx.html( |
| 123 | + """<svg width="338" height="478" viewBox="0 0 338 478" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| 124 | +<rect width="340" height="480" transform="translate(-1)" fill="url(#paint0_radial_10857_13090)"/> |
| 125 | +<defs> |
| 126 | +<radialGradient id="paint0_radial_10857_13090" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(170.501 240) rotate(-17.9215) scale(476.451 427.42)"> |
| 127 | +<stop offset="0.005434" stop-color="var(--c-slate-1)"/> |
| 128 | +<stop offset="1" stop-color="var(--c-slate-1)" stop-opacity="0"/> |
| 129 | +</radialGradient> |
| 130 | +</defs> |
| 131 | +</svg> |
| 132 | +""", |
| 133 | + class_name="shrink-0 absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 z-[-2] pointer-events-none", |
| 134 | + ), |
| 135 | + rx.box( |
| 136 | + rx.el.h2( |
| 137 | + "Powerful Outcomes", |
| 138 | + class_name="text-2xl font-semibold text-slate-12 text-center", |
| 139 | + ), |
| 140 | + rx.el.p( |
| 141 | + "Everything you need to achieve your goals", |
| 142 | + class_name="font-medium text-slate-9 text-center mt-2", |
| 143 | + ), |
| 144 | + rx.link( |
| 145 | + button( |
| 146 | + "Book Demo Now!", |
| 147 | + class_name="!h-10 mt-6 !font-small-smbold !rounded-[0.625rem] whitespace-nowrap w-48", |
| 148 | + ), |
| 149 | + underline="none", |
| 150 | + is_external=True, |
| 151 | + href="/pricing", |
| 152 | + ), |
| 153 | + class_name="flex flex-col justify-center items-center h-full", |
| 154 | + ), |
| 155 | + class_name="desktop-only h-full w-full flex flex-col justify-center items-center relative overflow-hidden row-span-2 col-span-1 border border-slate-3", |
| 156 | + ) |
| 157 | + |
| 158 | +def outcomes_card( |
| 159 | + title: str, |
| 160 | + description: str, |
| 161 | + icon: str, |
| 162 | + cols: str = "1", |
| 163 | + class_name: str = "", |
| 164 | +) -> rx.Component: |
| 165 | + """Individual outcomes feature card component.""" |
| 166 | + return rx.box( |
| 167 | + rx.box( |
| 168 | + _card_header(title, icon), |
| 169 | + _card_description(description), |
| 170 | + class_name="flex flex-col gap-[0.875rem]", |
| 171 | + ), |
| 172 | + class_name=f"col-span-{cols} h-[11rem] overflow-hidden p-8 w-full {class_name}", |
| 173 | + ) |
| 174 | + |
| 175 | +def _card_header(title: str, icon: str) -> rx.Component: |
| 176 | + """Card header with icon and title.""" |
| 177 | + return rx.box( |
| 178 | + get_icon(icon, class_name="!text-slate-9"), |
| 179 | + rx.el.h3(title, class_name="text-slate-12 text-base font-semibold"), |
| 180 | + class_name="flex flex-row items-center gap-2", |
| 181 | + ) |
| 182 | + |
| 183 | +def _card_description(description: str) -> rx.Component: |
| 184 | + """Card description text.""" |
| 185 | + return rx.el.p(description, class_name="text-slate-9 font-medium text-sm text-start") |
| 186 | + |
| 187 | +def _create_grid_items() -> List[rx.Component]: |
| 188 | + """Creates the grid items with outcomes showcase in the center.""" |
| 189 | + grid_items = [] |
| 190 | + |
| 191 | + # Add first outcomes card |
| 192 | + grid_items.append(outcomes_card(**OUTCOMES_FEATURES[0])) |
| 193 | + |
| 194 | + # Add the central outcomes showcase |
| 195 | + grid_items.append(outcomes_showcase()) |
| 196 | + |
| 197 | + # Add remaining outcomes cards |
| 198 | + for feature in OUTCOMES_FEATURES[1:]: |
| 199 | + grid_items.append(outcomes_card(**feature)) |
| 200 | + |
| 201 | + return grid_items |
| 202 | + |
| 203 | +def outcomes_grid() -> rx.Component: |
| 204 | + """Main outcomes features grid component.""" |
| 205 | + return rx.box( |
| 206 | + *_create_grid_items(), |
| 207 | + class_name="grid grid-cols-1 lg:grid-cols-3 gap-0 grid-rows-2 lg:grid-rows-2 w-full divide-y divide-slate-3 border border-slate-3", |
| 208 | + ) |
| 209 | + |
| 210 | +def outcomes_section() -> rx.Component: |
| 211 | + return rx.el.section( |
| 212 | + header(), |
| 213 | + rx.box( |
| 214 | + outcomes_grid(), |
| 215 | + class_name="flex flex-row max-w-[64.19rem] justify-center w-full", |
| 216 | + ), |
| 217 | + class_name="flex flex-col mx-auto w-full max-w-[84.19rem] relative justify-center items-center", |
| 218 | + ) |
0 commit comments