[{"data":1,"prerenderedAt":1320},["ShallowReactive",2],{"work-\u002Fwork\u002Frebuilding-capptions-website":3},{"id":4,"title":5,"body":6,"date":1304,"description":1305,"extension":1306,"externalUrl":1307,"featured":384,"kind":1308,"meta":1309,"navigation":384,"path":1311,"seo":1312,"stem":1313,"tags":1314,"__hash__":1319},"work\u002Fwork\u002Frebuilding-capptions-website.md","Rebuilding capptions.com - with next.js",{"type":7,"value":8,"toc":1292},"minimark",[9,13,21,26,29,32,36,39,74,78,83,241,245,259,262,713,720,723,925,929,936,939,1071,1077,1080,1186,1190,1222,1226,1229,1255,1259,1262,1280,1285,1288],[10,11,5],"h1",{"id":12},"rebuilding-capptionscom-with-nextjs",[14,15,16],"p",{},[17,18],"img",{"alt":19,"src":20},"The Capptions.com homepage I designed and built","\u002Fimages\u002Fcontent\u002Fcapptions-home.webp",[22,23,25],"h2",{"id":24},"context","Context",[14,27,28],{},"My journey to rebuilding Capptions.com started in an unexpected place: creating internal automation tools. As the Director of Marketing but also a passionate self-taught-developer at Capptions, I had been working on streamlining our internal processes through small automation projects. These projects, combined with my self-driven completion of CS50 (Harvard University), The Odin Project, and the Full Stack Open (FSO - University of Helsinki) courses, caught our CTO's attention. When the opportunity arose to rebuild our marketing website, I saw it as a chance to apply modern web development practices at scale.",[14,30,31],{},"The existing website was outdated and bloated – it wasn't serving our core audience of EHS (Environmental, Health, and Safety) directors and managers effectively. We needed a platform that could evolve quickly with our product offerings and market positioning, while maintaining top-tier performance and SEO standards.",[22,33,35],{"id":34},"what-i-built","What I Built",[14,37,38],{},"I created a modern, component-driven website using Next.js 14, with a focus on Server Components and optimal performance. The site serves as both our marketing platform and a technical showcase of our capabilities. Here's what makes it special:",[40,41,42,50,56,62,68],"ul",{},[43,44,45,49],"li",{},[46,47,48],"strong",{},"Component Library",": A comprehensive collection of 50+ reusable components, from simple UI elements to complex interactive features",[43,51,52,55],{},[46,53,54],{},"Performance-First Architecture",": Leveraging Next.js Server Components and static generation where possible",[43,57,58,61],{},[46,59,60],{},"Content Management",": Integration with Sanity CMS (though that's a story for another post!)",[43,63,64,67],{},[46,65,66],{},"Design System",": Custom implementation using TailwindCSS and ShadcnUI",[43,69,70,73],{},[46,71,72],{},"SEO Optimization",": Built-in SEO features with dynamic meta tags and structured data",[22,75,77],{"id":76},"technical-breakdown","Technical Breakdown",[79,80,82],"h3",{"id":81},"stack-selection","Stack Selection",[84,85,90],"pre",{"className":86,"code":87,"language":88,"meta":89,"style":89},"language-typescript shiki shiki-themes material-theme-lighter github-light github-dark","\u002F\u002F Example of our tech stack configuration\n{\n  framework: \"Next.js 14\",\n  styling: \"TailwindCSS\",\n  ui: \"ShadCN + Custom Components\",\n  deployment: \"Vercel\",\n  cms: \"Sanity\",\n  analytics: \"Posthog\",\n  typeChecking: \"TypeScript\",\n}\n","typescript","",[91,92,93,102,109,133,150,167,184,201,218,235],"code",{"__ignoreMap":89},[94,95,98],"span",{"class":96,"line":97},"line",1,[94,99,101],{"class":100},"sutJx","\u002F\u002F Example of our tech stack configuration\n",[94,103,105],{"class":96,"line":104},2,[94,106,108],{"class":107},"sP7_E","{\n",[94,110,112,116,119,123,127,130],{"class":96,"line":111},3,[94,113,115],{"class":114},"sbgvK","  framework",[94,117,118],{"class":107},":",[94,120,122],{"class":121},"sjJ54"," \"",[94,124,126],{"class":125},"s_sjI","Next.js 14",[94,128,129],{"class":121},"\"",[94,131,132],{"class":107},",\n",[94,134,136,139,141,143,146,148],{"class":96,"line":135},4,[94,137,138],{"class":114},"  styling",[94,140,118],{"class":107},[94,142,122],{"class":121},[94,144,145],{"class":125},"TailwindCSS",[94,147,129],{"class":121},[94,149,132],{"class":107},[94,151,153,156,158,160,163,165],{"class":96,"line":152},5,[94,154,155],{"class":114},"  ui",[94,157,118],{"class":107},[94,159,122],{"class":121},[94,161,162],{"class":125},"ShadCN + Custom Components",[94,164,129],{"class":121},[94,166,132],{"class":107},[94,168,170,173,175,177,180,182],{"class":96,"line":169},6,[94,171,172],{"class":114},"  deployment",[94,174,118],{"class":107},[94,176,122],{"class":121},[94,178,179],{"class":125},"Vercel",[94,181,129],{"class":121},[94,183,132],{"class":107},[94,185,187,190,192,194,197,199],{"class":96,"line":186},7,[94,188,189],{"class":114},"  cms",[94,191,118],{"class":107},[94,193,122],{"class":121},[94,195,196],{"class":125},"Sanity",[94,198,129],{"class":121},[94,200,132],{"class":107},[94,202,204,207,209,211,214,216],{"class":96,"line":203},8,[94,205,206],{"class":114},"  analytics",[94,208,118],{"class":107},[94,210,122],{"class":121},[94,212,213],{"class":125},"Posthog",[94,215,129],{"class":121},[94,217,132],{"class":107},[94,219,221,224,226,228,231,233],{"class":96,"line":220},9,[94,222,223],{"class":114},"  typeChecking",[94,225,118],{"class":107},[94,227,122],{"class":121},[94,229,230],{"class":125},"TypeScript",[94,232,129],{"class":121},[94,234,132],{"class":107},[94,236,238],{"class":96,"line":237},10,[94,239,240],{"class":107},"}\n",[79,242,244],{"id":243},"key-architectural-decisions","Key Architectural Decisions",[246,247,248,254],"ol",{},[43,249,250,253],{},[46,251,252],{},"Folder Structure","\nI implemented a feature-based architecture that scales with our growing needs:",[43,255,256],{},[46,257,258],{},"Performance Optimizations",[14,260,261],{},"One of my proudest achievements was implementing efficient component loading:",[84,263,265],{"className":86,"code":264,"language":88,"meta":89,"style":89},"\u002F\u002F components\u002Flazy-loading-wrapper.tsx\nexport const LazyLoadingWrapper = ({ children, threshold = 0.1 }) => {\n  const [isVisible, setIsVisible] = useState(false);\n  const ref = useRef(null);\n\n  useEffect(() => {\n    const observer = new IntersectionObserver(\n      ([entry]) => {\n        if (entry.isIntersecting) {\n          setIsVisible(true);\n          observer.disconnect();\n        }\n      },\n      { threshold },\n    );\n\n    if (ref.current) {\n      observer.observe(ref.current);\n    }\n\n    return () => observer.disconnect();\n  }, [threshold]);\n\n  return (\n    \u003Cdiv ref={ref}>\n      {isVisible ? children : \u003Cdiv className=\"h-[200px] animate-pulse\" \u002F>}\n    \u003C\u002Fdiv>\n  );\n};\n",[91,266,267,272,318,358,380,386,400,419,434,456,470,485,491,497,508,516,521,541,564,570,575,596,611,616,625,650,689,699,707],{"__ignoreMap":89},[94,268,269],{"class":96,"line":97},[94,270,271],{"class":100},"\u002F\u002F components\u002Flazy-loading-wrapper.tsx\n",[94,273,274,278,282,286,290,293,297,300,303,305,309,312,315],{"class":96,"line":104},[94,275,277],{"class":276},"sVHd0","export",[94,279,281],{"class":280},"sbsja"," const",[94,283,285],{"class":284},"sfCm-"," LazyLoadingWrapper",[94,287,289],{"class":288},"smGrS"," =",[94,291,292],{"class":107}," ({",[94,294,296],{"class":295},"s99_P"," children",[94,298,299],{"class":107},",",[94,301,302],{"class":295}," threshold",[94,304,289],{"class":288},[94,306,308],{"class":307},"srdBf"," 0.1",[94,310,311],{"class":107}," })",[94,313,314],{"class":280}," =>",[94,316,317],{"class":107}," {\n",[94,319,320,323,326,330,332,335,338,340,344,348,352,355],{"class":96,"line":111},[94,321,322],{"class":280},"  const",[94,324,325],{"class":107}," [",[94,327,329],{"class":328},"s_hVV","isVisible",[94,331,299],{"class":107},[94,333,334],{"class":328}," setIsVisible",[94,336,337],{"class":107},"]",[94,339,289],{"class":288},[94,341,343],{"class":342},"sGLFI"," useState",[94,345,347],{"class":346},"skxfh","(",[94,349,351],{"class":350},"syTEX","false",[94,353,354],{"class":346},")",[94,356,357],{"class":107},";\n",[94,359,360,362,365,367,370,372,376,378],{"class":96,"line":135},[94,361,322],{"class":280},[94,363,364],{"class":328}," ref",[94,366,289],{"class":288},[94,368,369],{"class":342}," useRef",[94,371,347],{"class":346},[94,373,375],{"class":374},"s39Yj","null",[94,377,354],{"class":346},[94,379,357],{"class":107},[94,381,382],{"class":96,"line":152},[94,383,385],{"emptyLinePlaceholder":384},true,"\n",[94,387,388,391,393,396,398],{"class":96,"line":169},[94,389,390],{"class":342},"  useEffect",[94,392,347],{"class":346},[94,394,395],{"class":107},"()",[94,397,314],{"class":280},[94,399,317],{"class":107},[94,401,402,405,408,410,413,416],{"class":96,"line":186},[94,403,404],{"class":280},"    const",[94,406,407],{"class":328}," observer",[94,409,289],{"class":288},[94,411,412],{"class":288}," new",[94,414,415],{"class":342}," IntersectionObserver",[94,417,418],{"class":346},"(\n",[94,420,421,424,427,430,432],{"class":96,"line":203},[94,422,423],{"class":107},"      ([",[94,425,426],{"class":295},"entry",[94,428,429],{"class":107},"])",[94,431,314],{"class":280},[94,433,317],{"class":107},[94,435,436,439,442,445,448,451,454],{"class":96,"line":220},[94,437,438],{"class":276},"        if",[94,440,441],{"class":346}," (",[94,443,426],{"class":444},"su5hD",[94,446,447],{"class":107},".",[94,449,450],{"class":444},"isIntersecting",[94,452,453],{"class":346},") ",[94,455,108],{"class":107},[94,457,458,461,463,466,468],{"class":96,"line":237},[94,459,460],{"class":342},"          setIsVisible",[94,462,347],{"class":346},[94,464,465],{"class":350},"true",[94,467,354],{"class":346},[94,469,357],{"class":107},[94,471,473,476,478,481,483],{"class":96,"line":472},11,[94,474,475],{"class":444},"          observer",[94,477,447],{"class":107},[94,479,480],{"class":342},"disconnect",[94,482,395],{"class":346},[94,484,357],{"class":107},[94,486,488],{"class":96,"line":487},12,[94,489,490],{"class":107},"        }\n",[94,492,494],{"class":96,"line":493},13,[94,495,496],{"class":107},"      },\n",[94,498,500,503,505],{"class":96,"line":499},14,[94,501,502],{"class":107},"      {",[94,504,302],{"class":444},[94,506,507],{"class":107}," },\n",[94,509,511,514],{"class":96,"line":510},15,[94,512,513],{"class":346},"    )",[94,515,357],{"class":107},[94,517,519],{"class":96,"line":518},16,[94,520,385],{"emptyLinePlaceholder":384},[94,522,524,527,529,532,534,537,539],{"class":96,"line":523},17,[94,525,526],{"class":276},"    if",[94,528,441],{"class":346},[94,530,531],{"class":444},"ref",[94,533,447],{"class":107},[94,535,536],{"class":444},"current",[94,538,453],{"class":346},[94,540,108],{"class":107},[94,542,544,547,549,552,554,556,558,560,562],{"class":96,"line":543},18,[94,545,546],{"class":444},"      observer",[94,548,447],{"class":107},[94,550,551],{"class":342},"observe",[94,553,347],{"class":346},[94,555,531],{"class":444},[94,557,447],{"class":107},[94,559,536],{"class":444},[94,561,354],{"class":346},[94,563,357],{"class":107},[94,565,567],{"class":96,"line":566},19,[94,568,569],{"class":107},"    }\n",[94,571,573],{"class":96,"line":572},20,[94,574,385],{"emptyLinePlaceholder":384},[94,576,578,581,584,586,588,590,592,594],{"class":96,"line":577},21,[94,579,580],{"class":276},"    return",[94,582,583],{"class":107}," ()",[94,585,314],{"class":280},[94,587,407],{"class":444},[94,589,447],{"class":107},[94,591,480],{"class":342},[94,593,395],{"class":346},[94,595,357],{"class":107},[94,597,599,602,604,607,609],{"class":96,"line":598},22,[94,600,601],{"class":107},"  },",[94,603,325],{"class":346},[94,605,606],{"class":444},"threshold",[94,608,429],{"class":346},[94,610,357],{"class":107},[94,612,614],{"class":96,"line":613},23,[94,615,385],{"emptyLinePlaceholder":384},[94,617,619,622],{"class":96,"line":618},24,[94,620,621],{"class":276},"  return",[94,623,624],{"class":346}," (\n",[94,626,628,631,634,636,639,642,644,647],{"class":96,"line":627},25,[94,629,630],{"class":288},"    \u003C",[94,632,633],{"class":444},"div",[94,635,364],{"class":444},[94,637,638],{"class":288},"=",[94,640,641],{"class":107},"{",[94,643,531],{"class":444},[94,645,646],{"class":107},"}",[94,648,649],{"class":288},">\n",[94,651,653,655,657,660,664,667,670,672,675,677,679,682,684,687],{"class":96,"line":652},26,[94,654,502],{"class":107},[94,656,329],{"class":295},[94,658,659],{"class":346}," ? ",[94,661,663],{"class":662},"sucvu","children",[94,665,666],{"class":107}," :",[94,668,669],{"class":346}," \u003C",[94,671,633],{"class":295},[94,673,674],{"class":295}," className",[94,676,638],{"class":288},[94,678,129],{"class":121},[94,680,681],{"class":125},"h-[200px] animate-pulse",[94,683,129],{"class":121},[94,685,686],{"class":288}," \u002F>",[94,688,240],{"class":107},[94,690,692,695,697],{"class":96,"line":691},27,[94,693,694],{"class":288},"    \u003C\u002F",[94,696,633],{"class":444},[94,698,649],{"class":288},[94,700,702,705],{"class":96,"line":701},28,[94,703,704],{"class":346},"  )",[94,706,357],{"class":107},[94,708,710],{"class":96,"line":709},29,[94,711,712],{"class":107},"};\n",[246,714,715],{"start":111},[43,716,717],{},[46,718,719],{},"Component Architecture",[14,721,722],{},"I developed a system of composable components that could be mixed and matched for different page layouts. Here's an example of our hero component structure:",[84,724,726],{"className":86,"code":725,"language":88,"meta":89,"style":89},"\u002F\u002F Simplified version of our hero component architecture\ninterface HeroProps {\n  variant: \"default\" | \"centered\" | \"split\";\n  title: string;\n  description: string;\n  cta?: {\n    text: string;\n    href: string;\n  };\n}\n\nexport const Hero: React.FC\u003CHeroProps> = ({\n  variant,\n  title,\n  description,\n  cta,\n}) => {\n  \u002F\u002F Component logic\n};\n",[91,727,728,733,743,778,791,802,812,823,834,839,843,847,881,887,893,899,905,916,921],{"__ignoreMap":89},[94,729,730],{"class":96,"line":97},[94,731,732],{"class":100},"\u002F\u002F Simplified version of our hero component architecture\n",[94,734,735,738,741],{"class":96,"line":104},[94,736,737],{"class":280},"interface",[94,739,740],{"class":114}," HeroProps",[94,742,317],{"class":107},[94,744,745,748,750,752,755,757,760,762,765,767,769,771,774,776],{"class":96,"line":111},[94,746,747],{"class":662},"  variant",[94,749,118],{"class":288},[94,751,122],{"class":121},[94,753,754],{"class":125},"default",[94,756,129],{"class":121},[94,758,759],{"class":288}," |",[94,761,122],{"class":121},[94,763,764],{"class":125},"centered",[94,766,129],{"class":121},[94,768,759],{"class":288},[94,770,122],{"class":121},[94,772,773],{"class":125},"split",[94,775,129],{"class":121},[94,777,357],{"class":107},[94,779,780,783,785,789],{"class":96,"line":135},[94,781,782],{"class":662},"  title",[94,784,118],{"class":288},[94,786,788],{"class":787},"sZMiF"," string",[94,790,357],{"class":107},[94,792,793,796,798,800],{"class":96,"line":152},[94,794,795],{"class":662},"  description",[94,797,118],{"class":288},[94,799,788],{"class":787},[94,801,357],{"class":107},[94,803,804,807,810],{"class":96,"line":169},[94,805,806],{"class":662},"  cta",[94,808,809],{"class":288},"?:",[94,811,317],{"class":107},[94,813,814,817,819,821],{"class":96,"line":186},[94,815,816],{"class":662},"    text",[94,818,118],{"class":288},[94,820,788],{"class":787},[94,822,357],{"class":107},[94,824,825,828,830,832],{"class":96,"line":203},[94,826,827],{"class":662},"    href",[94,829,118],{"class":288},[94,831,788],{"class":787},[94,833,357],{"class":107},[94,835,836],{"class":96,"line":220},[94,837,838],{"class":107},"  };\n",[94,840,841],{"class":96,"line":237},[94,842,240],{"class":107},[94,844,845],{"class":96,"line":472},[94,846,385],{"emptyLinePlaceholder":384},[94,848,849,851,853,856,858,861,863,866,869,872,875,877,879],{"class":96,"line":487},[94,850,277],{"class":276},[94,852,281],{"class":280},[94,854,855],{"class":284}," Hero",[94,857,118],{"class":288},[94,859,860],{"class":114}," React",[94,862,447],{"class":107},[94,864,865],{"class":114},"FC",[94,867,868],{"class":107},"\u003C",[94,870,871],{"class":114},"HeroProps",[94,873,874],{"class":107},">",[94,876,289],{"class":288},[94,878,441],{"class":444},[94,880,108],{"class":107},[94,882,883,885],{"class":96,"line":493},[94,884,747],{"class":444},[94,886,132],{"class":107},[94,888,889,891],{"class":96,"line":499},[94,890,782],{"class":444},[94,892,132],{"class":107},[94,894,895,897],{"class":96,"line":510},[94,896,795],{"class":444},[94,898,132],{"class":107},[94,900,901,903],{"class":96,"line":518},[94,902,806],{"class":444},[94,904,132],{"class":107},[94,906,907,909,911,914],{"class":96,"line":523},[94,908,646],{"class":107},[94,910,453],{"class":444},[94,912,913],{"class":280},"=>",[94,915,317],{"class":107},[94,917,918],{"class":96,"line":543},[94,919,920],{"class":100},"  \u002F\u002F Component logic\n",[94,922,923],{"class":96,"line":566},[94,924,712],{"class":107},[79,926,928],{"id":927},"challenges-and-solutions","Challenges and Solutions",[246,930,931],{},[43,932,933],{},[46,934,935],{},"Performance vs. Rich Interactions",[14,937,938],{},"One of the biggest challenges was balancing rich interactive features with performance. I solved this through strategic code splitting and lazy loading:",[84,940,942],{"className":86,"code":941,"language":88,"meta":89,"style":89},"\u002F\u002F Example of how we handle dynamic imports\nconst DynamicWorkflowBuilder = dynamic(\n  () =>\n    import(\"@\u002Fcomponents\u002Fworkflow-builder-drawer\").then(\n      (mod) => mod.WorkflowBuilder,\n    ),\n  {\n    loading: () => \u003CLoadingSpinner \u002F>,\n    ssr: false,\n  },\n);\n",[91,943,944,949,964,972,995,1017,1023,1028,1048,1060,1065],{"__ignoreMap":89},[94,945,946],{"class":96,"line":97},[94,947,948],{"class":100},"\u002F\u002F Example of how we handle dynamic imports\n",[94,950,951,954,957,959,962],{"class":96,"line":104},[94,952,953],{"class":280},"const",[94,955,956],{"class":328}," DynamicWorkflowBuilder",[94,958,289],{"class":288},[94,960,961],{"class":342}," dynamic",[94,963,418],{"class":444},[94,965,966,969],{"class":96,"line":111},[94,967,968],{"class":107},"  ()",[94,970,971],{"class":280}," =>\n",[94,973,974,977,979,981,984,986,988,990,993],{"class":96,"line":135},[94,975,976],{"class":288},"    import",[94,978,347],{"class":444},[94,980,129],{"class":121},[94,982,983],{"class":125},"@\u002Fcomponents\u002Fworkflow-builder-drawer",[94,985,129],{"class":121},[94,987,354],{"class":444},[94,989,447],{"class":107},[94,991,992],{"class":342},"then",[94,994,418],{"class":444},[94,996,997,1000,1003,1005,1007,1010,1012,1015],{"class":96,"line":152},[94,998,999],{"class":107},"      (",[94,1001,1002],{"class":295},"mod",[94,1004,354],{"class":107},[94,1006,314],{"class":280},[94,1008,1009],{"class":444}," mod",[94,1011,447],{"class":107},[94,1013,1014],{"class":444},"WorkflowBuilder",[94,1016,132],{"class":107},[94,1018,1019,1021],{"class":96,"line":169},[94,1020,513],{"class":444},[94,1022,132],{"class":107},[94,1024,1025],{"class":96,"line":186},[94,1026,1027],{"class":107},"  {\n",[94,1029,1030,1033,1035,1037,1039,1041,1044,1046],{"class":96,"line":203},[94,1031,1032],{"class":342},"    loading",[94,1034,118],{"class":107},[94,1036,583],{"class":107},[94,1038,314],{"class":280},[94,1040,669],{"class":444},[94,1042,1043],{"class":114},"LoadingSpinner",[94,1045,686],{"class":444},[94,1047,132],{"class":107},[94,1049,1050,1053,1055,1058],{"class":96,"line":220},[94,1051,1052],{"class":346},"    ssr",[94,1054,118],{"class":107},[94,1056,1057],{"class":350}," false",[94,1059,132],{"class":107},[94,1061,1062],{"class":96,"line":237},[94,1063,1064],{"class":107},"  },\n",[94,1066,1067,1069],{"class":96,"line":472},[94,1068,354],{"class":444},[94,1070,357],{"class":107},[246,1072,1073],{"start":104},[43,1074,1075],{},[46,1076,72],{},[14,1078,1079],{},"I implemented a robust SEO strategy using Next.js's metadata API:",[84,1081,1083],{"className":86,"code":1082,"language":88,"meta":89,"style":89},"\u002F\u002F app\u002F(main)\u002Flayout.tsx\nexport const metadata: Metadata = {\n  metadataBase: new URL(\"https:\u002F\u002Fcapptions.com\"),\n  title: {\n    default: \"Capptions - EHS & ESG Compliance Software\",\n    template: \"%s | Capptions\",\n  },\n  \u002F\u002F ... other metadata\n};\n",[91,1084,1085,1090,1108,1133,1141,1157,1173,1177,1182],{"__ignoreMap":89},[94,1086,1087],{"class":96,"line":97},[94,1088,1089],{"class":100},"\u002F\u002F app\u002F(main)\u002Flayout.tsx\n",[94,1091,1092,1094,1096,1099,1101,1104,1106],{"class":96,"line":104},[94,1093,277],{"class":276},[94,1095,281],{"class":280},[94,1097,1098],{"class":328}," metadata",[94,1100,118],{"class":288},[94,1102,1103],{"class":114}," Metadata",[94,1105,289],{"class":288},[94,1107,317],{"class":107},[94,1109,1110,1113,1115,1117,1120,1122,1124,1127,1129,1131],{"class":96,"line":111},[94,1111,1112],{"class":346},"  metadataBase",[94,1114,118],{"class":107},[94,1116,412],{"class":288},[94,1118,1119],{"class":342}," URL",[94,1121,347],{"class":444},[94,1123,129],{"class":121},[94,1125,1126],{"class":125},"https:\u002F\u002Fcapptions.com",[94,1128,129],{"class":121},[94,1130,354],{"class":444},[94,1132,132],{"class":107},[94,1134,1135,1137,1139],{"class":96,"line":135},[94,1136,782],{"class":346},[94,1138,118],{"class":107},[94,1140,317],{"class":107},[94,1142,1143,1146,1148,1150,1153,1155],{"class":96,"line":152},[94,1144,1145],{"class":346},"    default",[94,1147,118],{"class":107},[94,1149,122],{"class":121},[94,1151,1152],{"class":125},"Capptions - EHS & ESG Compliance Software",[94,1154,129],{"class":121},[94,1156,132],{"class":107},[94,1158,1159,1162,1164,1166,1169,1171],{"class":96,"line":169},[94,1160,1161],{"class":346},"    template",[94,1163,118],{"class":107},[94,1165,122],{"class":121},[94,1167,1168],{"class":125},"%s | Capptions",[94,1170,129],{"class":121},[94,1172,132],{"class":107},[94,1174,1175],{"class":96,"line":186},[94,1176,1064],{"class":107},[94,1178,1179],{"class":96,"line":203},[94,1180,1181],{"class":100},"  \u002F\u002F ... other metadata\n",[94,1183,1184],{"class":96,"line":220},[94,1185,712],{"class":107},[22,1187,1189],{"id":1188},"what-i-learned","What I Learned",[246,1191,1192,1198,1204,1210,1216],{},[43,1193,1194,1197],{},[46,1195,1196],{},"Server Components Are Game-Changing","\nMoving from a client-heavy approach to Server Components dramatically improved our initial page load times and SEO capabilities.",[43,1199,1200,1203],{},[46,1201,1202],{},"Type Safety Pays Off","\nTypeScript's strict mode caught countless potential issues before they hit production. The initial investment in proper typing saved hours of debugging.",[43,1205,1206,1209],{},[46,1207,1208],{},"Component Architecture Evolution","\nI learned to start with smaller, more focused components and compose them into larger features, rather than building monolithic components that are hard to maintain.",[43,1211,1212,1215],{},[46,1213,1214],{},"Userflow Monitoring is Crucial","\nSetting up Posthog early helped us identify and fix userflow bottlenecks before they impacted users.",[43,1217,1218,1221],{},[46,1219,1220],{},"Performance Monitoring is Crucial","\nRunning Lighthouse tests on the website helped me identify and fix performance bottlenecks before they impacted users.",[22,1223,1225],{"id":1224},"whats-next","What's Next",[14,1227,1228],{},"The website is never \"done\" – it's a living project that evolves with our business needs. Here's what's on the horizon:",[246,1230,1231,1237,1243,1249],{},[43,1232,1233,1236],{},[46,1234,1235],{},"A\u002FB Testing Infrastructure",": Building a system to test different messaging and layouts",[43,1238,1239,1242],{},[46,1240,1241],{},"Enhanced Personalization",": Implementing user-specific content based on industry, role, and use-case.",[43,1244,1245,1248],{},[46,1246,1247],{},"Performance Optimization",": Continuing to optimize for Core Web Vitals",[43,1250,1251,1254],{},[46,1252,1253],{},"Internationalization",": Expanding our language support beyond English",[22,1256,1258],{"id":1257},"impact-and-results","Impact and Results",[14,1260,1261],{},"The rebuild has had significant business impact:",[40,1263,1264,1267,1274,1277],{},[43,1265,1266],{},"90% improvement in Core Web Vitals scores",[43,1268,1269,1270],{},"10x faster deployment cycles ",[1271,1272,1273],"em",{},"(previously we were limited to only content changes, now we can rapidly deploy new features, pages, layouts etc.)",[43,1275,1276],{},"30% increase in lead generation form submissions",[43,1278,1279],{},"Significantly improved developer experience for content updates",[14,1281,1282],{},[1271,1283,1284],{},"(I'm now able to make changes to the website without having to wait for an external developer to do it for me: as I am the developer)",[14,1286,1287],{},"Honestly, this project wasn't just about \"building a website\" – it was about creating a solid foundation for Capptions' digital presence that could scale and evolve. It's a strong (single handed) mix of design, content (visual and written), and development. The trust placed in me by our CTO to take on this project has led to even more opportunities to innovate and improve our technical infrastructure.",[1289,1290,1291],"style",{},"html pre.shiki code .sutJx, html code.shiki .sutJx{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sbgvK, html code.shiki .sbgvK{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sjJ54, html code.shiki .sjJ54{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sVHd0, html code.shiki .sVHd0{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit}html pre.shiki code .sbsja, html code.shiki .sbsja{--shiki-light:#9C3EDA;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sfCm-, html code.shiki .sfCm-{--shiki-light:#90A4AE;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .s99_P, html code.shiki .s99_P{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#E36209;--shiki-default-font-style:inherit;--shiki-dark:#FFAB70;--shiki-dark-font-style:inherit}html pre.shiki code .srdBf, html code.shiki .srdBf{--shiki-light:#F76D47;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .s_hVV, html code.shiki .s_hVV{--shiki-light:#90A4AE;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sGLFI, html code.shiki .sGLFI{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .skxfh, html code.shiki .skxfh{--shiki-light:#E53935;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .syTEX, html code.shiki .syTEX{--shiki-light:#FF5370;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .s39Yj, html code.shiki .s39Yj{--shiki-light:#39ADB5;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sucvu, html code.shiki .sucvu{--shiki-light:#E53935;--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sZMiF, html code.shiki .sZMiF{--shiki-light:#E2931D;--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":89,"searchDepth":104,"depth":104,"links":1293},[1294,1295,1296,1301,1302,1303],{"id":24,"depth":104,"text":25},{"id":34,"depth":104,"text":35},{"id":76,"depth":104,"text":77,"children":1297},[1298,1299,1300],{"id":81,"depth":111,"text":82},{"id":243,"depth":111,"text":244},{"id":927,"depth":111,"text":928},{"id":1188,"depth":104,"text":1189},{"id":1224,"depth":104,"text":1225},{"id":1257,"depth":104,"text":1258},"2024-03-24","How I transformed our company's web presence by rebuilding Capptions.com from scratch using Next.js, focusing on performance, maintainability, and rapid iteration.","md",null,"case-study",{"author":1310},"Ajoy Gonsalves","\u002Fwork\u002Frebuilding-capptions-website",{"title":5,"description":1305},"work\u002Frebuilding-capptions-website",[1315,230,145,1316,179,1317,1318],"Next.js","ShadcnUI","Performance","SEO","QumHivbjZBJlaHlt3GzkVl4w3QoRquiU5KTya5tU7-c",1780955296664]