-- Dumping data for table `craft_matrixblocktypes`
--

set autocommit=0;
INSERT INTO `craft_matrixblocktypes` VALUES (1,6,19,'Big Screenshot','bigScreenshot',1,'2014-01-18 04:22:41','2017-09-07 21:53:27','5f36ea81-76de-484e-bc2f-2b7fbcdfd4ba'),(2,6,20,'Small Screenshot','smallScreenshot',2,'2014-01-18 04:22:42','2017-09-07 21:53:27','8dbf5901-f68e-4d1d-a7e0-3d3564633caf'),(3,11,22,'Fact','fact',1,'2014-01-18 21:33:17','2019-10-09 15:56:06','9841c1ec-e327-414e-8606-0629dfa49f62'),(4,20,39,'Code','code',2,'2023-01-26 15:20:29','2023-01-26 15:20:29','306075d5-6875-4386-87f7-5458431def30'),(5,20,40,'Text','text',1,'2023-01-26 15:20:29','2023-01-26 15:20:29','4dab73a6-3747-4e23-95b2-5b094733276c'),(6,25,44,'Experience','experience',1,'2024-04-15 18:28:07','2024-04-15 18:28:07','1544212f-c3ab-43df-8088-1ce9d50f2375');
commit;

--
-- Dumping data for table `craft_matrixcontent_bodyblocks`
--

set autocommit=0;
INSERT INTO `craft_matrixcontent_bodyblocks` VALUES (110,2640,1,'2023-01-26 15:55:05','2023-01-26 22:17:44','d4741d57-a18f-4ece-b11f-31c3458e089e',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"//assets.trevor-davis.com/uploads/images/content/like-component.mp4\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(111,2641,1,'2023-01-26 15:55:05','2023-01-26 22:17:44','b73cb947-5d3a-4f4a-98d9-32242d47ccc0','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(112,2642,1,'2023-01-26 15:55:05','2023-01-26 22:17:44','236c02ca-1872-483c-b22c-f36243d52b40',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(113,2643,1,'2023-01-26 15:55:05','2023-01-26 22:17:44','856e31a7-c4f3-49c4-8815-69c122f3dd0a','ReferenceError: window is not defined','text',NULL),(114,2644,1,'2023-01-26 15:55:05','2023-01-26 22:17:44','39431e25-dd21-41f6-9e6f-3722d1ff9171',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(115,2645,1,'2023-01-26 15:55:05','2023-01-26 22:17:44','60ebe326-224e-4ae3-920a-f8f86bcc4642','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(116,2646,1,'2023-01-26 15:55:05','2023-01-26 22:17:44','6e7aeead-b920-4f3a-95f9-37efd5560c7f',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(234,2772,1,'2023-01-26 22:35:53','2023-01-26 22:41:42','4bab497b-0135-4a06-963f-eb6a3b7336c2',NULL,NULL,'<p>In my <a href=\"https://www.trevor-davis.com/blog/why-im-so-excited-about-remix\">previous post</a>, I talked about transitioning my site from being powered by <a href=\"https://craftcms.com/\">Craft</a> to being powered by <a href=\"https://remix.run/\">Remix</a> and a GraphQL endpoint coming from Craft. One of the best features of Craft is <a href=\"https://craftcms.com/features/all#live-preview\">Live Preview</a>, and it took a little configuration to get this working on my new Remix powered site.</p>\r\n<h2>Remix Configuration</h2>\r\n<p>These were specific changes that I needed to make on the Remix side, but really it would be the same for any GraphQL request. As Andrew Welch breaks down in <a href=\"https://nystudio107.com/blog/headless-preview-in-craft-cms\">his article</a>, the key is passing the token parameter back that Craft included in the URL.</p>\r\n<p>In the loader function of my blog post route, I call a helper function to setup the GraphQL client, and I pass the request to it:</p>'),(235,2773,1,'2023-01-26 22:35:53','2023-01-26 22:41:42','ea876e85-fa08-40a3-a0b6-0b461456a49b','import { json } from \'remix\'\nimport { gql } from \'graphql-request\'\nimport { gqlClient } from \'graphql.server\'\n\nexport const loader = async ({ request }) => {\n    const { entries } = await gqlClient(request).request(gql`\n        {\n            YOUR GRAPHQL QUERY HERE\n        }\n    `)\n\n    return json({ entries })\n}','jsx',NULL),(236,2774,1,'2023-01-26 22:35:53','2023-01-26 22:41:42','0018cbea-c2ec-46a6-adf9-41be937cfc0b',NULL,NULL,'<p>And then in my helper function, I take that request, grab the URL params that I want to include, and add those to my GraphQL request endpoint URL:</p>'),(237,2775,1,'2023-01-26 22:35:53','2023-01-26 22:41:42','cc4c6a77-9a36-4fb0-92fc-7ed39595145b','import { GraphQLClient } from \'graphql-request\'\n\n// Extract allowed query params and construct query string\nconst getQueryParams = (request) => {\n    const url = new URL(request.url)\n    const allowedKeys = [\'x-craft-preview\', \'x-craft-live-preview\', \'token\']\n    const filteredParams = Object.entries(\n        Object.fromEntries(url.searchParams)\n    ).filter(([key]) => allowedKeys.includes(key))\n\n    if (!filteredParams.length) {\n        return \'\'\n    }\n\n    const queryString = filteredParams.map((val) => val.join(\'=\')).join(\'&\')\n\n    return `?${queryString}`\n}\n\nexport const gqlClient = (request = null) => {\n    const queryString = request ? getQueryParams(request) : \'\'\n\n    return new GraphQLClient(`https://your-endpoint-here/${queryString}`, {\n        headers: {\n            authorization: `Bearer YOUR_AUTH_TOKEN_HERE`,\n        },\n    })\n}','jsx',NULL),(238,2776,1,'2023-01-26 22:35:53','2023-01-26 22:41:42','1c02fac1-925b-40ff-8831-3396f447c3e3',NULL,NULL,'<p>It wasn’t totally necessary to include the <code>x-craft-preview</code> and <code>x-craft-live-preview</code> parameters, but I figured it couldn’t hurt.</p>\r\n<h2>Craft Configuration</h2>\r\n<p>Now with the Remix configuration in place, I just needed to make two small changes to Craft to get it working correctly. First, I had to update the preview target for my Blog section to point to my Remix site:</p>\r\n<figure><img src=\"{asset:2283:url||//assets.trevor-davis.com/uploads/images/content/blog-section-preview-target.png}\" data-image=\"2283\" alt=\"Setting the preview target in my Blog Section\"></figure>\r\n<p>Then, I had to update the <code>config/general.php</code> to allow iframe requests from my Remix domain:</p>'),(239,2777,1,'2023-01-26 22:35:53','2023-01-26 22:41:42','eb2b3109-102b-4d82-802a-9d6b0e4dd7cd','<?php\n\nreturn [\n    \'*\' => [\n        \'headlessMode\' => true,\n        \'previewIframeResizerOptions\' => [\n            \'checkOrigin\' => [\n                \'https://www.trevor-davis.com\',\n            ],\n        ],\n    ],\n];','php',NULL),(240,2778,1,'2023-01-26 22:35:53','2023-01-26 22:41:42','f013d8ce-0c0d-4142-a8cb-2b4d34ae7e37',NULL,NULL,'<h2>Voilà, Live Preview</h2>\r\n<p>And just like that, I had live preview working.</p>\r\n<p><video src=\"//assets.trevor-davis.com/uploads/images/content/live-preview.mp4\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\" width=\"100%\"></video></p>'),(241,2780,1,'2023-01-26 22:35:53','2023-01-26 22:35:53','c2434d0c-3224-482c-90d0-eb6df6c21158',NULL,NULL,'<p>In my <a href=\"https://www.trevor-davis.com/blog/why-im-so-excited-about-remix\">previous post</a>, I talked about transitioning my site from being powered by <a href=\"https://craftcms.com/\">Craft</a> to being powered by <a href=\"https://remix.run/\">Remix</a> and a GraphQL endpoint coming from Craft. One of the best features of Craft is <a href=\"https://craftcms.com/features/all#live-preview\">Live Preview</a>, and it took a little configuration to get this working on my new Remix powered site.</p>\r\n<h2>Remix Configuration</h2>\r\n<p>These were specific changes that I needed to make on the Remix side, but really it would be the same for any GraphQL request. As Andrew Welch breaks down in <a href=\"https://nystudio107.com/blog/headless-preview-in-craft-cms\">his article</a>, the key is passing the token parameter back that Craft included in the URL.</p>\r\n<p>In the loader function of my blog post route, I call a helper function to setup the GraphQL client, and I pass the request to it:</p>'),(242,2781,1,'2023-01-26 22:35:53','2023-01-26 22:35:53','eea35156-8a54-4f75-ba78-16c041187cad','import { json } from \'remix\'\nimport { gql } from \'graphql-request\'\nimport { gqlClient } from \'graphql.server\'\n\nexport const loader = async ({ request }) => {\n    const { entries } = await gqlClient(request).request(gql`\n        {\n            YOUR GRAPHQL QUERY HERE\n        }\n    `)\n\n    return json({ entries })\n}','jsx',NULL),(243,2782,1,'2023-01-26 22:35:53','2023-01-26 22:35:53','bd655dfe-66cb-44e5-9340-749a6e9a2330',NULL,NULL,'<p>And then in my helper function, I take that request, grab the URL params that I want to include, and add those to my GraphQL request endpoint URL:</p>'),(244,2783,1,'2023-01-26 22:35:53','2023-01-26 22:35:53','ab900cb5-5aff-4757-9bc7-ea3986289af8','import { GraphQLClient } from \'graphql-request\'\n\n// Pass through allowed query params to the requst\nconst getQueryParams = (request) => {\n    const url = new URL(request.url)\n    const allowedKeys = [\'x-craft-preview\', \'x-craft-live-preview\', \'token\']\n    const filteredParams = Object.entries(\n        Object.fromEntries(url.searchParams)\n    ).filter(([key]) => allowedKeys.includes(key))\n\n    if (!filteredParams.length) {\n        return \'\'\n    }\n\n    const queryString = filteredParams.map((val) => val.join(\'=\')).join(\'&\')\n\n    return `?${queryString}`\n}\n\nexport const gqlClient = (request = null) => {\n    const queryString = request ? getQueryParams(request) : \'\'\n\n    return new GraphQLClient(`https://your-endpoint-here/${queryString}`, {\n        headers: {\n            authorization: `Bearer YOUR_AUTH_TOKEN_HERE`,\n        },\n    })\n}','jsx',NULL),(245,2784,1,'2023-01-26 22:35:53','2023-01-26 22:35:53','fa40dc1b-f7e9-48fc-b2c7-c2a049995c85',NULL,NULL,'<p>It wasn’t totally necessary to include the <code>x-craft-preview</code> and <code>x-craft-live-preview</code> parameters, but I figured it couldn’t hurt.</p>\r\n<h2>Craft Configuration</h2>\r\n<p>Now with the Remix configuration in place, I just needed to make two small changes to Craft to get it working correctly. First, I had to update the preview target for my Blog section to point to my Remix site:</p>\r\n<figure><img src=\"{asset:2283:url||//assets.trevor-davis.com/uploads/images/content/blog-section-preview-target.png}\" data-image=\"2283\" alt=\"Setting the preview target in my Blog Section\"></figure>\r\n<p>Then, I had to update the <code>config/general.php</code> to allow iframe requests from my Remix domain:</p>'),(246,2785,1,'2023-01-26 22:35:53','2023-01-26 22:35:53','c616a82c-9f11-4f07-8485-77f426aad923','<?php\n\nreturn [\n    \'*\' => [\n        \'headlessMode\' => true,\n        \'previewIframeResizerOptions\' => [\n            \'checkOrigin\' => [\n                \'https://www.trevor-davis.com\',\n            ],\n        ],\n    ],\n];','php',NULL),(247,2786,1,'2023-01-26 22:35:53','2023-01-26 22:35:53','27f0ae65-5dd9-4883-994b-1704c1876c0a',NULL,NULL,'<h2>Voilà, Live Preview</h2>\r\n<p>And just like that, I had live preview working.</p>\r\n<p><video src=\"//assets.trevor-davis.com/uploads/images/content/live-preview.mp4\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\" width=\"100%\"></video></p>'),(255,2796,1,'2023-01-26 22:36:56','2023-01-26 22:36:56','726bcc64-b759-4d07-b774-24395cc44fe2',NULL,NULL,'<p>In my <a href=\"https://www.trevor-davis.com/blog/why-im-so-excited-about-remix\">previous post</a>, I talked about transitioning my site from being powered by <a href=\"https://craftcms.com/\">Craft</a> to being powered by <a href=\"https://remix.run/\">Remix</a> and a GraphQL endpoint coming from Craft. One of the best features of Craft is <a href=\"https://craftcms.com/features/all#live-preview\">Live Preview</a>, and it took a little configuration to get this working on my new Remix powered site.</p>\r\n<h2>Remix Configuration</h2>\r\n<p>These were specific changes that I needed to make on the Remix side, but really it would be the same for any GraphQL request. As Andrew Welch breaks down in <a href=\"https://nystudio107.com/blog/headless-preview-in-craft-cms\">his article</a>, the key is passing the token parameter back that Craft included in the URL.</p>\r\n<p>In the loader function of my blog post route, I call a helper function to setup the GraphQL client, and I pass the request to it:</p>'),(256,2797,1,'2023-01-26 22:36:56','2023-01-26 22:36:56','e66ac0d7-4b06-4cdc-a054-7d659362c7b8','import { json } from \'remix\'\nimport { gql } from \'graphql-request\'\nimport { gqlClient } from \'graphql.server\'\n\nexport const loader = async ({ request }) => {\n    const { entries } = await gqlClient(request).request(gql`\n        {\n            YOUR GRAPHQL QUERY HERE\n        }\n    `)\n\n    return json({ entries })\n}','jsx',NULL),(257,2798,1,'2023-01-26 22:36:56','2023-01-26 22:36:56','c0958a82-02ba-479f-a40a-0455b2e9e4f1',NULL,NULL,'<p>And then in my helper function, I take that request, grab the URL params that I want to include, and add those to my GraphQL request endpoint URL:</p>'),(258,2799,1,'2023-01-26 22:36:56','2023-01-26 22:36:56','b6b437c7-e782-4925-b8b9-966c4d91e8ce','import { GraphQLClient } from \'graphql-request\'\n\n/* Pass through allowed query params to the request */\nconst getQueryParams = (request) => {\n    const url = new URL(request.url)\n    const allowedKeys = [\'x-craft-preview\', \'x-craft-live-preview\', \'token\']\n    const filteredParams = Object.entries(\n        Object.fromEntries(url.searchParams)\n    ).filter(([key]) => allowedKeys.includes(key))\n\n    if (!filteredParams.length) {\n        return \'\'\n    }\n\n    const queryString = filteredParams.map((val) => val.join(\'=\')).join(\'&\')\n\n    return `?${queryString}`\n}\n\nexport const gqlClient = (request = null) => {\n    const queryString = request ? getQueryParams(request) : \'\'\n\n    return new GraphQLClient(`https://your-endpoint-here/${queryString}`, {\n        headers: {\n            authorization: `Bearer YOUR_AUTH_TOKEN_HERE`,\n        },\n    })\n}','jsx',NULL),(259,2800,1,'2023-01-26 22:36:56','2023-01-26 22:36:56','d6f2bd1a-09b2-4de7-abd7-23d443c70305',NULL,NULL,'<p>It wasn’t totally necessary to include the <code>x-craft-preview</code> and <code>x-craft-live-preview</code> parameters, but I figured it couldn’t hurt.</p>\r\n<h2>Craft Configuration</h2>\r\n<p>Now with the Remix configuration in place, I just needed to make two small changes to Craft to get it working correctly. First, I had to update the preview target for my Blog section to point to my Remix site:</p>\r\n<figure><img src=\"{asset:2283:url||//assets.trevor-davis.com/uploads/images/content/blog-section-preview-target.png}\" data-image=\"2283\" alt=\"Setting the preview target in my Blog Section\"></figure>\r\n<p>Then, I had to update the <code>config/general.php</code> to allow iframe requests from my Remix domain:</p>'),(260,2801,1,'2023-01-26 22:36:57','2023-01-26 22:36:57','4721f389-e03d-47ef-b56a-44c1812fa751','<?php\n\nreturn [\n    \'*\' => [\n        \'headlessMode\' => true,\n        \'previewIframeResizerOptions\' => [\n            \'checkOrigin\' => [\n                \'https://www.trevor-davis.com\',\n            ],\n        ],\n    ],\n];','php',NULL),(261,2802,1,'2023-01-26 22:36:57','2023-01-26 22:36:57','ecf4a3c4-5df0-4084-915a-1281c383f363',NULL,NULL,'<h2>Voilà, Live Preview</h2>\r\n<p>And just like that, I had live preview working.</p>\r\n<p><video src=\"//assets.trevor-davis.com/uploads/images/content/live-preview.mp4\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\" width=\"100%\"></video></p>'),(269,2812,1,'2023-01-26 22:37:15','2023-01-26 22:37:15','c3e6ea50-33a5-4695-bf25-690ae278ea56',NULL,NULL,'<p>In my <a href=\"https://www.trevor-davis.com/blog/why-im-so-excited-about-remix\">previous post</a>, I talked about transitioning my site from being powered by <a href=\"https://craftcms.com/\">Craft</a> to being powered by <a href=\"https://remix.run/\">Remix</a> and a GraphQL endpoint coming from Craft. One of the best features of Craft is <a href=\"https://craftcms.com/features/all#live-preview\">Live Preview</a>, and it took a little configuration to get this working on my new Remix powered site.</p>\r\n<h2>Remix Configuration</h2>\r\n<p>These were specific changes that I needed to make on the Remix side, but really it would be the same for any GraphQL request. As Andrew Welch breaks down in <a href=\"https://nystudio107.com/blog/headless-preview-in-craft-cms\">his article</a>, the key is passing the token parameter back that Craft included in the URL.</p>\r\n<p>In the loader function of my blog post route, I call a helper function to setup the GraphQL client, and I pass the request to it:</p>'),(270,2813,1,'2023-01-26 22:37:15','2023-01-26 22:37:15','21bf019c-b40a-479d-a0d5-608b6426a5ae','import { json } from \'remix\'\nimport { gql } from \'graphql-request\'\nimport { gqlClient } from \'graphql.server\'\n\nexport const loader = async ({ request }) => {\n    const { entries } = await gqlClient(request).request(gql`\n        {\n            YOUR GRAPHQL QUERY HERE\n        }\n    `)\n\n    return json({ entries })\n}','jsx',NULL),(271,2814,1,'2023-01-26 22:37:15','2023-01-26 22:37:15','4b6b1816-999d-4c4a-8a1b-c93b82d28825',NULL,NULL,'<p>And then in my helper function, I take that request, grab the URL params that I want to include, and add those to my GraphQL request endpoint URL:</p>'),(272,2815,1,'2023-01-26 22:37:15','2023-01-26 22:37:15','b293d837-93a3-43de-8558-d617c002bf48','import { GraphQLClient } from \'graphql-request\'\n\n// Pass through allowed query params to the request\n\nconst getQueryParams = (request) => {\n    const url = new URL(request.url)\n    const allowedKeys = [\'x-craft-preview\', \'x-craft-live-preview\', \'token\']\n    const filteredParams = Object.entries(\n        Object.fromEntries(url.searchParams)\n    ).filter(([key]) => allowedKeys.includes(key))\n\n    if (!filteredParams.length) {\n        return \'\'\n    }\n\n    const queryString = filteredParams.map((val) => val.join(\'=\')).join(\'&\')\n\n    return `?${queryString}`\n}\n\nexport const gqlClient = (request = null) => {\n    const queryString = request ? getQueryParams(request) : \'\'\n\n    return new GraphQLClient(`https://your-endpoint-here/${queryString}`, {\n        headers: {\n            authorization: `Bearer YOUR_AUTH_TOKEN_HERE`,\n        },\n    })\n}','jsx',NULL),(273,2816,1,'2023-01-26 22:37:15','2023-01-26 22:37:15','4cd8d8c2-8e61-42cd-b05f-ee0815379aa5',NULL,NULL,'<p>It wasn’t totally necessary to include the <code>x-craft-preview</code> and <code>x-craft-live-preview</code> parameters, but I figured it couldn’t hurt.</p>\r\n<h2>Craft Configuration</h2>\r\n<p>Now with the Remix configuration in place, I just needed to make two small changes to Craft to get it working correctly. First, I had to update the preview target for my Blog section to point to my Remix site:</p>\r\n<figure><img src=\"{asset:2283:url||//assets.trevor-davis.com/uploads/images/content/blog-section-preview-target.png}\" data-image=\"2283\" alt=\"Setting the preview target in my Blog Section\"></figure>\r\n<p>Then, I had to update the <code>config/general.php</code> to allow iframe requests from my Remix domain:</p>'),(274,2817,1,'2023-01-26 22:37:15','2023-01-26 22:37:15','b2eec4cc-70ba-40cd-8847-52c5eec88e0a','<?php\n\nreturn [\n    \'*\' => [\n        \'headlessMode\' => true,\n        \'previewIframeResizerOptions\' => [\n            \'checkOrigin\' => [\n                \'https://www.trevor-davis.com\',\n            ],\n        ],\n    ],\n];','php',NULL),(275,2818,1,'2023-01-26 22:37:15','2023-01-26 22:37:15','1c325d20-a098-46cb-80c3-1c1bca4782af',NULL,NULL,'<h2>Voilà, Live Preview</h2>\r\n<p>And just like that, I had live preview working.</p>\r\n<p><video src=\"//assets.trevor-davis.com/uploads/images/content/live-preview.mp4\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\" width=\"100%\"></video></p>'),(283,2828,1,'2023-01-26 22:38:04','2023-01-26 22:38:04','74eae194-7790-4442-af3d-2eb8e70ebedd',NULL,NULL,'<p>In my <a href=\"https://www.trevor-davis.com/blog/why-im-so-excited-about-remix\">previous post</a>, I talked about transitioning my site from being powered by <a href=\"https://craftcms.com/\">Craft</a> to being powered by <a href=\"https://remix.run/\">Remix</a> and a GraphQL endpoint coming from Craft. One of the best features of Craft is <a href=\"https://craftcms.com/features/all#live-preview\">Live Preview</a>, and it took a little configuration to get this working on my new Remix powered site.</p>\r\n<h2>Remix Configuration</h2>\r\n<p>These were specific changes that I needed to make on the Remix side, but really it would be the same for any GraphQL request. As Andrew Welch breaks down in <a href=\"https://nystudio107.com/blog/headless-preview-in-craft-cms\">his article</a>, the key is passing the token parameter back that Craft included in the URL.</p>\r\n<p>In the loader function of my blog post route, I call a helper function to setup the GraphQL client, and I pass the request to it:</p>'),(284,2829,1,'2023-01-26 22:38:04','2023-01-26 22:38:04','d9665592-6ba4-4d1a-8b2c-8a17e0016cb5','import { json } from \'remix\'\nimport { gql } from \'graphql-request\'\nimport { gqlClient } from \'graphql.server\'\n\nexport const loader = async ({ request }) => {\n    const { entries } = await gqlClient(request).request(gql`\n        {\n            YOUR GRAPHQL QUERY HERE\n        }\n    `)\n\n    return json({ entries })\n}','jsx',NULL),(285,2830,1,'2023-01-26 22:38:04','2023-01-26 22:38:04','b3523f94-d2b3-442c-9ecf-b6decb2e264d',NULL,NULL,'<p>And then in my helper function, I take that request, grab the URL params that I want to include, and add those to my GraphQL request endpoint URL:</p>'),(286,2831,1,'2023-01-26 22:38:04','2023-01-26 22:38:04','928be380-fdf4-4acb-a13f-2b942fbad101','import { GraphQLClient } from \'graphql-request\'\n\n// Pass through allowed query params to the request\nconst getQueryParams = (request) => {\n    const url = new URL(request.url)\n    const allowedKeys = [\'x-craft-preview\', \'x-craft-live-preview\', \'token\']\n    const filteredParams = Object.entries(\n        Object.fromEntries(url.searchParams)\n    ).filter(([key]) => allowedKeys.includes(key))\n\n    if (!filteredParams.length) {\n        return \'\'\n    }\n\n    const queryString = filteredParams.map((val) => val.join(\'=\')).join(\'&\')\n\n    return `?${queryString}`\n}\n\nexport const gqlClient = (request = null) => {\n    const queryString = request ? getQueryParams(request) : \'\'\n\n    return new GraphQLClient(`https://your-endpoint-here/${queryString}`, {\n        headers: {\n            authorization: `Bearer YOUR_AUTH_TOKEN_HERE`,\n        },\n    })\n}','jsx',NULL),(287,2832,1,'2023-01-26 22:38:04','2023-01-26 22:38:04','3aff7423-f396-4a22-a3b8-fb4e38a26990',NULL,NULL,'<p>It wasn’t totally necessary to include the <code>x-craft-preview</code> and <code>x-craft-live-preview</code> parameters, but I figured it couldn’t hurt.</p>\r\n<h2>Craft Configuration</h2>\r\n<p>Now with the Remix configuration in place, I just needed to make two small changes to Craft to get it working correctly. First, I had to update the preview target for my Blog section to point to my Remix site:</p>\r\n<figure><img src=\"{asset:2283:url||//assets.trevor-davis.com/uploads/images/content/blog-section-preview-target.png}\" data-image=\"2283\" alt=\"Setting the preview target in my Blog Section\"></figure>\r\n<p>Then, I had to update the <code>config/general.php</code> to allow iframe requests from my Remix domain:</p>'),(288,2833,1,'2023-01-26 22:38:04','2023-01-26 22:38:04','e3dda9f4-030d-4ca3-b189-ab20b532ba07','<?php\n\nreturn [\n    \'*\' => [\n        \'headlessMode\' => true,\n        \'previewIframeResizerOptions\' => [\n            \'checkOrigin\' => [\n                \'https://www.trevor-davis.com\',\n            ],\n        ],\n    ],\n];','php',NULL),(289,2834,1,'2023-01-26 22:38:04','2023-01-26 22:38:04','1181e00b-3aa1-45c7-a6c7-2b9b19805ee3',NULL,NULL,'<h2>Voilà, Live Preview</h2>\r\n<p>And just like that, I had live preview working.</p>\r\n<p><video src=\"//assets.trevor-davis.com/uploads/images/content/live-preview.mp4\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\" width=\"100%\"></video></p>'),(297,2844,1,'2023-01-26 22:40:54','2023-01-26 22:40:54','043f1387-5b16-469d-868d-828713eacf44',NULL,NULL,'<p>In my <a href=\"https://www.trevor-davis.com/blog/why-im-so-excited-about-remix\">previous post</a>, I talked about transitioning my site from being powered by <a href=\"https://craftcms.com/\">Craft</a> to being powered by <a href=\"https://remix.run/\">Remix</a> and a GraphQL endpoint coming from Craft. One of the best features of Craft is <a href=\"https://craftcms.com/features/all#live-preview\">Live Preview</a>, and it took a little configuration to get this working on my new Remix powered site.</p>\r\n<h2>Remix Configuration</h2>\r\n<p>These were specific changes that I needed to make on the Remix side, but really it would be the same for any GraphQL request. As Andrew Welch breaks down in <a href=\"https://nystudio107.com/blog/headless-preview-in-craft-cms\">his article</a>, the key is passing the token parameter back that Craft included in the URL.</p>\r\n<p>In the loader function of my blog post route, I call a helper function to setup the GraphQL client, and I pass the request to it:</p>'),(298,2845,1,'2023-01-26 22:40:54','2023-01-26 22:40:54','b2b704e6-f101-4272-8e0c-7b98b44e0cdf','import { json } from \'remix\'\nimport { gql } from \'graphql-request\'\nimport { gqlClient } from \'graphql.server\'\n\nexport const loader = async ({ request }) => {\n    const { entries } = await gqlClient(request).request(gql`\n        {\n            YOUR GRAPHQL QUERY HERE\n        }\n    `)\n\n    return json({ entries })\n}','jsx',NULL),(299,2846,1,'2023-01-26 22:40:54','2023-01-26 22:40:54','c29a030f-b3f2-4818-8ee3-d3bea1ce347a',NULL,NULL,'<p>And then in my helper function, I take that request, grab the URL params that I want to include, and add those to my GraphQL request endpoint URL:</p>'),(300,2847,1,'2023-01-26 22:40:54','2023-01-26 22:40:54','393edf3d-209e-4931-aaa9-7123a7d9847a','import { GraphQLClient } from \'graphql-request\'\n\n{/* Extract allowed query params and construct query string */}\nconst getQueryParams = (request) => {\n    const url = new URL(request.url)\n    const allowedKeys = [\'x-craft-preview\', \'x-craft-live-preview\', \'token\']\n    const filteredParams = Object.entries(\n        Object.fromEntries(url.searchParams)\n    ).filter(([key]) => allowedKeys.includes(key))\n\n    if (!filteredParams.length) {\n        return \'\'\n    }\n\n    const queryString = filteredParams.map((val) => val.join(\'=\')).join(\'&\')\n\n    return `?${queryString}`\n}\n\nexport const gqlClient = (request = null) => {\n    const queryString = request ? getQueryParams(request) : \'\'\n\n    return new GraphQLClient(`https://your-endpoint-here/${queryString}`, {\n        headers: {\n            authorization: `Bearer YOUR_AUTH_TOKEN_HERE`,\n        },\n    })\n}','jsx',NULL),(301,2848,1,'2023-01-26 22:40:54','2023-01-26 22:40:54','69c74d27-e4aa-44bd-9514-db63c22c624b',NULL,NULL,'<p>It wasn’t totally necessary to include the <code>x-craft-preview</code> and <code>x-craft-live-preview</code> parameters, but I figured it couldn’t hurt.</p>\r\n<h2>Craft Configuration</h2>\r\n<p>Now with the Remix configuration in place, I just needed to make two small changes to Craft to get it working correctly. First, I had to update the preview target for my Blog section to point to my Remix site:</p>\r\n<figure><img src=\"{asset:2283:url||//assets.trevor-davis.com/uploads/images/content/blog-section-preview-target.png}\" data-image=\"2283\" alt=\"Setting the preview target in my Blog Section\"></figure>\r\n<p>Then, I had to update the <code>config/general.php</code> to allow iframe requests from my Remix domain:</p>'),(302,2849,1,'2023-01-26 22:40:54','2023-01-26 22:40:54','92ece704-59ea-4723-b8b5-4b2426252b91','<?php\n\nreturn [\n    \'*\' => [\n        \'headlessMode\' => true,\n        \'previewIframeResizerOptions\' => [\n            \'checkOrigin\' => [\n                \'https://www.trevor-davis.com\',\n            ],\n        ],\n    ],\n];','php',NULL),(303,2850,1,'2023-01-26 22:40:54','2023-01-26 22:40:54','bdec5bd3-9c6c-4de8-b2e6-812bc7c2277e',NULL,NULL,'<h2>Voilà, Live Preview</h2>\r\n<p>And just like that, I had live preview working.</p>\r\n<p><video src=\"//assets.trevor-davis.com/uploads/images/content/live-preview.mp4\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\" width=\"100%\"></video></p>'),(311,2860,1,'2023-01-26 22:41:11','2023-01-26 22:41:11','60925ca2-68a1-47ab-aae4-7d7dbb9e6009',NULL,NULL,'<p>In my <a href=\"https://www.trevor-davis.com/blog/why-im-so-excited-about-remix\">previous post</a>, I talked about transitioning my site from being powered by <a href=\"https://craftcms.com/\">Craft</a> to being powered by <a href=\"https://remix.run/\">Remix</a> and a GraphQL endpoint coming from Craft. One of the best features of Craft is <a href=\"https://craftcms.com/features/all#live-preview\">Live Preview</a>, and it took a little configuration to get this working on my new Remix powered site.</p>\r\n<h2>Remix Configuration</h2>\r\n<p>These were specific changes that I needed to make on the Remix side, but really it would be the same for any GraphQL request. As Andrew Welch breaks down in <a href=\"https://nystudio107.com/blog/headless-preview-in-craft-cms\">his article</a>, the key is passing the token parameter back that Craft included in the URL.</p>\r\n<p>In the loader function of my blog post route, I call a helper function to setup the GraphQL client, and I pass the request to it:</p>'),(312,2861,1,'2023-01-26 22:41:12','2023-01-26 22:41:12','3f8f07f8-ce0a-4f61-8257-a1fd91c606c4','import { json } from \'remix\'\nimport { gql } from \'graphql-request\'\nimport { gqlClient } from \'graphql.server\'\n\nexport const loader = async ({ request }) => {\n    const { entries } = await gqlClient(request).request(gql`\n        {\n            YOUR GRAPHQL QUERY HERE\n        }\n    `)\n\n    return json({ entries })\n}','jsx',NULL),(313,2862,1,'2023-01-26 22:41:12','2023-01-26 22:41:12','c93933b9-9434-4f49-8445-e195f7d17c20',NULL,NULL,'<p>And then in my helper function, I take that request, grab the URL params that I want to include, and add those to my GraphQL request endpoint URL:</p>'),(314,2863,1,'2023-01-26 22:41:12','2023-01-26 22:41:12','31512ea7-0ba6-4b19-8849-ac4aa3b39a60','import { GraphQLClient } from \'graphql-request\'\n\n{\n    /* Extract allowed query params and construct query string */\n}\n\nconst getQueryParams = (request) => {\n    const url = new URL(request.url)\n    const allowedKeys = [\'x-craft-preview\', \'x-craft-live-preview\', \'token\']\n    const filteredParams = Object.entries(\n        Object.fromEntries(url.searchParams)\n    ).filter(([key]) => allowedKeys.includes(key))\n\n    if (!filteredParams.length) {\n        return \'\'\n    }\n\n    const queryString = filteredParams.map((val) => val.join(\'=\')).join(\'&\')\n\n    return `?${queryString}`\n}\n\nexport const gqlClient = (request = null) => {\n    const queryString = request ? getQueryParams(request) : \'\'\n\n    return new GraphQLClient(`https://your-endpoint-here/${queryString}`, {\n        headers: {\n            authorization: `Bearer YOUR_AUTH_TOKEN_HERE`,\n        },\n    })\n}','jsx',NULL),(315,2864,1,'2023-01-26 22:41:12','2023-01-26 22:41:12','c2f87ca8-45bc-4052-91e4-6b5ec4b32687',NULL,NULL,'<p>It wasn’t totally necessary to include the <code>x-craft-preview</code> and <code>x-craft-live-preview</code> parameters, but I figured it couldn’t hurt.</p>\r\n<h2>Craft Configuration</h2>\r\n<p>Now with the Remix configuration in place, I just needed to make two small changes to Craft to get it working correctly. First, I had to update the preview target for my Blog section to point to my Remix site:</p>\r\n<figure><img src=\"{asset:2283:url||//assets.trevor-davis.com/uploads/images/content/blog-section-preview-target.png}\" data-image=\"2283\" alt=\"Setting the preview target in my Blog Section\"></figure>\r\n<p>Then, I had to update the <code>config/general.php</code> to allow iframe requests from my Remix domain:</p>'),(316,2865,1,'2023-01-26 22:41:12','2023-01-26 22:41:12','da7d6216-ca69-4c81-bc99-ca676b9d8f7c','<?php\n\nreturn [\n    \'*\' => [\n        \'headlessMode\' => true,\n        \'previewIframeResizerOptions\' => [\n            \'checkOrigin\' => [\n                \'https://www.trevor-davis.com\',\n            ],\n        ],\n    ],\n];','php',NULL),(317,2866,1,'2023-01-26 22:41:12','2023-01-26 22:41:12','545f285f-05e2-4cc1-889e-f7b1bece9e04',NULL,NULL,'<h2>Voilà, Live Preview</h2>\r\n<p>And just like that, I had live preview working.</p>\r\n<p><video src=\"//assets.trevor-davis.com/uploads/images/content/live-preview.mp4\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\" width=\"100%\"></video></p>'),(318,2868,1,'2023-01-26 22:41:23','2023-01-26 22:41:23','74f9b356-e249-4a07-a8f6-0b28afb91675',NULL,NULL,'<p>In my <a href=\"https://www.trevor-davis.com/blog/why-im-so-excited-about-remix\">previous post</a>, I talked about transitioning my site from being powered by <a href=\"https://craftcms.com/\">Craft</a> to being powered by <a href=\"https://remix.run/\">Remix</a> and a GraphQL endpoint coming from Craft. One of the best features of Craft is <a href=\"https://craftcms.com/features/all#live-preview\">Live Preview</a>, and it took a little configuration to get this working on my new Remix powered site.</p>\r\n<h2>Remix Configuration</h2>\r\n<p>These were specific changes that I needed to make on the Remix side, but really it would be the same for any GraphQL request. As Andrew Welch breaks down in <a href=\"https://nystudio107.com/blog/headless-preview-in-craft-cms\">his article</a>, the key is passing the token parameter back that Craft included in the URL.</p>\r\n<p>In the loader function of my blog post route, I call a helper function to setup the GraphQL client, and I pass the request to it:</p>'),(319,2869,1,'2023-01-26 22:41:23','2023-01-26 22:41:23','e78bdf87-5949-4a7f-9cb2-ea513c3f582d','import { json } from \'remix\'\nimport { gql } from \'graphql-request\'\nimport { gqlClient } from \'graphql.server\'\n\nexport const loader = async ({ request }) => {\n    const { entries } = await gqlClient(request).request(gql`\n        {\n            YOUR GRAPHQL QUERY HERE\n        }\n    `)\n\n    return json({ entries })\n}','jsx',NULL),(320,2870,1,'2023-01-26 22:41:23','2023-01-26 22:41:23','e16c7730-7017-4ef9-b521-1965876d3b6d',NULL,NULL,'<p>And then in my helper function, I take that request, grab the URL params that I want to include, and add those to my GraphQL request endpoint URL:</p>'),(321,2871,1,'2023-01-26 22:41:23','2023-01-26 22:41:23','22e4d14a-3cc8-4efe-beb7-b99cbd83fb43','import { GraphQLClient } from \'graphql-request\'\n\nconst getQueryParams = (request) => {\n    const url = new URL(request.url)\n    const allowedKeys = [\'x-craft-preview\', \'x-craft-live-preview\', \'token\']\n    const filteredParams = Object.entries(\n        Object.fromEntries(url.searchParams)\n    ).filter(([key]) => allowedKeys.includes(key))\n\n    if (!filteredParams.length) {\n        return \'\'\n    }\n\n    const queryString = filteredParams.map((val) => val.join(\'=\')).join(\'&\')\n\n    return `?${queryString}`\n}\n\nexport const gqlClient = (request = null) => {\n    const queryString = request ? getQueryParams(request) : \'\'\n\n    return new GraphQLClient(`https://your-endpoint-here/${queryString}`, {\n        headers: {\n            authorization: `Bearer YOUR_AUTH_TOKEN_HERE`,\n        },\n    })\n}','jsx',NULL),(322,2872,1,'2023-01-26 22:41:23','2023-01-26 22:41:23','e26a0a17-75d7-4c7d-b1ea-d0b722ef3c77',NULL,NULL,'<p>It wasn’t totally necessary to include the <code>x-craft-preview</code> and <code>x-craft-live-preview</code> parameters, but I figured it couldn’t hurt.</p>\r\n<h2>Craft Configuration</h2>\r\n<p>Now with the Remix configuration in place, I just needed to make two small changes to Craft to get it working correctly. First, I had to update the preview target for my Blog section to point to my Remix site:</p>\r\n<figure><img src=\"{asset:2283:url||//assets.trevor-davis.com/uploads/images/content/blog-section-preview-target.png}\" data-image=\"2283\" alt=\"Setting the preview target in my Blog Section\"></figure>\r\n<p>Then, I had to update the <code>config/general.php</code> to allow iframe requests from my Remix domain:</p>'),(323,2873,1,'2023-01-26 22:41:23','2023-01-26 22:41:23','dcd3964f-4541-4e8d-876a-a37bc361d431','<?php\n\nreturn [\n    \'*\' => [\n        \'headlessMode\' => true,\n        \'previewIframeResizerOptions\' => [\n            \'checkOrigin\' => [\n                \'https://www.trevor-davis.com\',\n            ],\n        ],\n    ],\n];','php',NULL),(324,2874,1,'2023-01-26 22:41:23','2023-01-26 22:41:23','3a4bed41-dd15-4e5b-b57a-2fe3edd9093d',NULL,NULL,'<h2>Voilà, Live Preview</h2>\r\n<p>And just like that, I had live preview working.</p>\r\n<p><video src=\"//assets.trevor-davis.com/uploads/images/content/live-preview.mp4\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\" width=\"100%\"></video></p>'),(332,2884,1,'2023-01-26 22:41:42','2023-01-26 22:41:42','f94ec615-d228-4526-b550-fe9bc3741adf',NULL,NULL,'<p>In my <a href=\"https://www.trevor-davis.com/blog/why-im-so-excited-about-remix\">previous post</a>, I talked about transitioning my site from being powered by <a href=\"https://craftcms.com/\">Craft</a> to being powered by <a href=\"https://remix.run/\">Remix</a> and a GraphQL endpoint coming from Craft. One of the best features of Craft is <a href=\"https://craftcms.com/features/all#live-preview\">Live Preview</a>, and it took a little configuration to get this working on my new Remix powered site.</p>\r\n<h2>Remix Configuration</h2>\r\n<p>These were specific changes that I needed to make on the Remix side, but really it would be the same for any GraphQL request. As Andrew Welch breaks down in <a href=\"https://nystudio107.com/blog/headless-preview-in-craft-cms\">his article</a>, the key is passing the token parameter back that Craft included in the URL.</p>\r\n<p>In the loader function of my blog post route, I call a helper function to setup the GraphQL client, and I pass the request to it:</p>'),(333,2885,1,'2023-01-26 22:41:42','2023-01-26 22:41:42','154ef73f-c635-4655-bdc2-7ba7e99f7dfc','import { json } from \'remix\'\nimport { gql } from \'graphql-request\'\nimport { gqlClient } from \'graphql.server\'\n\nexport const loader = async ({ request }) => {\n    const { entries } = await gqlClient(request).request(gql`\n        {\n            YOUR GRAPHQL QUERY HERE\n        }\n    `)\n\n    return json({ entries })\n}','jsx',NULL),(334,2886,1,'2023-01-26 22:41:42','2023-01-26 22:41:42','dda82868-a360-4242-8803-89dca6fe1cff',NULL,NULL,'<p>And then in my helper function, I take that request, grab the URL params that I want to include, and add those to my GraphQL request endpoint URL:</p>'),(335,2887,1,'2023-01-26 22:41:42','2023-01-26 22:41:42','2aedb5a2-8816-429c-a2f7-a4af0354ff9c','import { GraphQLClient } from \'graphql-request\'\n\n// Extract allowed query params and construct query string\nconst getQueryParams = (request) => {\n    const url = new URL(request.url)\n    const allowedKeys = [\'x-craft-preview\', \'x-craft-live-preview\', \'token\']\n    const filteredParams = Object.entries(\n        Object.fromEntries(url.searchParams)\n    ).filter(([key]) => allowedKeys.includes(key))\n\n    if (!filteredParams.length) {\n        return \'\'\n    }\n\n    const queryString = filteredParams.map((val) => val.join(\'=\')).join(\'&\')\n\n    return `?${queryString}`\n}\n\nexport const gqlClient = (request = null) => {\n    const queryString = request ? getQueryParams(request) : \'\'\n\n    return new GraphQLClient(`https://your-endpoint-here/${queryString}`, {\n        headers: {\n            authorization: `Bearer YOUR_AUTH_TOKEN_HERE`,\n        },\n    })\n}','jsx',NULL),(336,2888,1,'2023-01-26 22:41:42','2023-01-26 22:41:42','1836b308-b32c-467b-8f52-04082c316432',NULL,NULL,'<p>It wasn’t totally necessary to include the <code>x-craft-preview</code> and <code>x-craft-live-preview</code> parameters, but I figured it couldn’t hurt.</p>\r\n<h2>Craft Configuration</h2>\r\n<p>Now with the Remix configuration in place, I just needed to make two small changes to Craft to get it working correctly. First, I had to update the preview target for my Blog section to point to my Remix site:</p>\r\n<figure><img src=\"{asset:2283:url||//assets.trevor-davis.com/uploads/images/content/blog-section-preview-target.png}\" data-image=\"2283\" alt=\"Setting the preview target in my Blog Section\"></figure>\r\n<p>Then, I had to update the <code>config/general.php</code> to allow iframe requests from my Remix domain:</p>'),(337,2889,1,'2023-01-26 22:41:42','2023-01-26 22:41:42','d5936f29-6778-4742-97fe-59ca47352fd4','<?php\n\nreturn [\n    \'*\' => [\n        \'headlessMode\' => true,\n        \'previewIframeResizerOptions\' => [\n            \'checkOrigin\' => [\n                \'https://www.trevor-davis.com\',\n            ],\n        ],\n    ],\n];','php',NULL),(338,2890,1,'2023-01-26 22:41:42','2023-01-26 22:41:42','775c298c-3e29-43d6-8e84-3004e4268484',NULL,NULL,'<h2>Voilà, Live Preview</h2>\r\n<p>And just like that, I had live preview working.</p>\r\n<p><video src=\"//assets.trevor-davis.com/uploads/images/content/live-preview.mp4\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\" width=\"100%\"></video></p>'),(389,2942,1,'2023-01-27 14:50:36','2023-01-27 14:50:36','f61aa654-f503-4543-bf97-20e4766919f7',NULL,NULL,'<p>I’ve been building on the web for a long time. There’s a part of me that still has a bit of an old school mentality, and it’s hard for me to get really excited about new technology. Sure React was cool when it came out for its state management, but I didn’t see it as the be-all and end-all for building on the web. I really like <a href=\"https://craftcms.com/\">Craft CMS</a> for building CMS powered sites since I have full control over the HTML being sent to the browser, and it’s really easy to extend for complex functionality, but it can be a bit complex to setup for beginners and with additional complexity can come performance issues.&nbsp;So it’s been a while since I’ve seen something to be <em>really</em> excited about.</p>\r\n<p>Enter <a href=\"https://remix.run/\">Remix</a>.</p>\r\n<p>Remix is an interesting mix of old school techniques along with modern technology. Ryan Florence actually sums it up perfectly as to where Remix fits in.</p>\r\n<blockquote class=\"twitter-tweet\" data-dnt=\"true\" data-theme=\"dark\"><p lang=\"en\" dir=\"ltr\">Forget “full stack”. Remix is center stack.<br><br>It’s an HTTP tunnel between interactivity and business logic. It’s the part of the stack that no tool before it has solved, not completely.<br><br>I think I finally know how to talk about Remix.</p>— Ryan Florence (@ryanflorence) <a href=\"https://twitter.com/ryanflorence/status/1482233495195770883?ref_src=twsrc%5Etfw\">January 15, 2022</a></blockquote>\r\n<script async=\"\" src=\"https://platform.twitter.com/widgets.js\" charset=\"utf-8\"></script>\r\n<p>I was able to easily switch my site that was fully powered by Craft to utilize Craft only as a GraphQL endpoint and Remix powering the rest. The two big things I needed to figure out were: how to get data from the GraphQL endpoint, and then how to process input from a user (for my contact form). I would definitely recommend reading through the Remix docs and the two tutorials, but if you can understand these two big pictures things, you’ll have enough to get started with Remix and go deeper once you get into it.</p>\r\n<h2>Getting GraphQL Data (aka Loaders)</h2>\r\n<p>Remix provides a <a href=\"https://remix.run/docs/en/v1/api/conventions#loader\">loader hook</a> that runs on the server to hydrate your component. In this simple example, I run a GraphQL request and return JSON with the results of that request in the loader function.</p>'),(390,2943,1,'2023-01-27 14:50:36','2023-01-27 14:50:36','801a99f1-71f1-4355-90ac-5ff07f90911e','import { GraphQLClient } from \'graphql-request\'\nimport { gql } from \'graphql-request\'\nimport { useLoaderData, json } from \'remix\'\n\nconst endpoint = \'https://your-endpoint-here/\'\nconst options = {\n    headers: {\n        authorization: \'Bearer YOUR_AUTH_TOKEN_HERE\',\n    }\n}\n\nconst EntriesQuery = gql`\n    {\n        YOUR GRAPHQL QUERY HERE\n    }\n`\n\nexport const loader = async () => {\n    const { entries } = new GraphQLClient(endpoint, options).request(EntriesQuery)\n\n    return json({\n        entries\n    })\n}\n\nexport default function Index() {\n    const data = useLoaderData()\n\n    return (\n        <>\n            {data.entries.map((entry) => (\n                <div key={entry.id}>\n                    {entry.title}\n                </div>\n            ))}\n        </>\n    )\n}','jsx',NULL),(391,2944,1,'2023-01-27 14:50:36','2023-01-27 14:50:36','84e83b36-ecfa-47de-8ef3-c1c9fe64a2c2',NULL,NULL,'<p>Then in my <code>Index</code> component, I access the data from the loader hook with <a href=\"https://remix.run/docs/en/v1/api/remix#useloaderdata\">useLoaderData()</a>, and my component is now hydrated with that data. In MVC style of thinking, think of the loader hook as the controller processing the page load request, populating with data from the model, and then passing to the view.</p>\r\n<p>The great part about Remix is that this doesn’t have to be specifically a GraphQL request. This data can come from anywhere. The <a href=\"https://remix.run/docs/en/v1/tutorials/jokes\">Jokes tutorial</a> in the Remix docs even thoroughly walks through how you can manage all this data in <a href=\"https://www.prisma.io/\">Prisma</a>.</p>\r\n<h2>Processing User Input (aka Actions)</h2>\r\n<p>Ok great, so we’ve got data onto the page, but now we need to be able to handle user input. Remix also provides an <a href=\"https://remix.run/docs/en/v1/api/conventions#action\">action hook</a> to process an action request (ex: a form submission). In my case, I have a contact form that sends me an email via SendGrid after submission.</p>'),(392,2945,1,'2023-01-27 14:50:36','2023-01-27 14:50:36','4982c5ca-15b6-4412-845f-dcaabfacc125','import {\n    useActionData,\n    Form,\n    redirect,\n    json\n} from \'remix\'\n\nexport async function action({ request }) {\n    const formData = await request.formData()\n    const errors = {}\n    \n    // Do data validation and add to the errors object if there are any errors\n    \n    if (Object.keys(errors).length) {\n        return json(errors, { status: 422 })\n    }\n    \n    // No errors: send email, store in DB, do whatever you need to do with the form data\n    \n    return redirect(\'/contact/thanks\')\n}\n\nexport default function ContactIndex() {\n    const errors = useActionData()\n    \n    return (\n        <Form method=\"post\">\n        </Form>\n    )\n}','jsx',NULL),(393,2946,1,'2023-01-27 14:50:36','2023-01-27 14:50:36','b1025e8e-2539-429e-a561-46a8c21a34fe',NULL,NULL,'<p>If you don’t include an <code>action</code> attribute on your form, it will automatically submit to the same page. Again, in MVC thinking, the action would again be equivalent to the controller taking the request input and processing it. But honestly, this takes me back 15 years when form actions would point directly to PHP files.</p>\r\n<h2>Bonus: Progressive Enhancement</h2>\r\n<p>Since Remix is running on the server, you can turn off JavaScript and everything still works great. Data still loads, form actions still process; it’s beautiful. This is not running loaders and actions on the client side; it’s running them on the server. This isn’t an accident, the Remix team is carefully considering the UX.</p>\r\n<blockquote class=\"twitter-tweet\" data-dnt=\"true\" data-theme=\"dark\"><p lang=\"en\" dir=\"ltr\">User experience (UX) and developer experience (DX) are both important. UX is more important than DX.<a href=\"https://twitter.com/remix_run?ref_src=twsrc%5Etfw\">@remix_run</a> has taught me: It\'s easier to start with a great UX and work toward a good DX than it is to start with a great DX and work toward a good UX.</p>— Kent C. Dodds &#x1f4bf; (@kentcdodds) <a href=\"https://twitter.com/kentcdodds/status/1482390454389805058?ref_src=twsrc%5Etfw\">January 15, 2022</a></blockquote>\r\n<script async=\"\" src=\"https://platform.twitter.com/widgets.js\" charset=\"utf-8\"></script>\r\n<h2>Bonus: So Speedy</h2>\r\n<p>Did I mention how fast everything renders? I don’t tend to put too much stock into Lighthouse scores since they seem so random, but Remix crushes Lighthouse without me having to invest any additional effort into improving performance.</p>\r\n<h2>Give it a Shot</h2>\r\n<p>Remix is built on the <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API\">native Fetch API</a>, so it can run anywhere. While Remix is relatively new, it’s certainly production ready, and there is a dedicated team behind it. If you aren’t ready to dive into Remix yet, at least keep your eye on it because this is a game changer.</p>'),(394,2948,1,'2023-01-27 14:50:36','2023-01-27 14:50:36','abd2ee45-86b2-4bf3-98cf-dddaeb4d170e',NULL,NULL,'<p>I’ve been building on the web for a long time. There’s a part of me that still has a bit of an old school mentality, and it’s hard for me to get really excited about new technology. Sure React was cool when it came out for its state management, but I didn’t see it as the be-all and end-all for building on the web. I really like <a href=\"https://craftcms.com/\">Craft CMS</a> for building CMS powered sites since I have full control over the HTML being sent to the browser, and it’s really easy to extend for complex functionality, but it can be a bit complex to setup for beginners and with additional complexity can come performance issues.&nbsp;So it’s been a while since I’ve seen something to be <em>really</em> excited about.</p>\r\n<p>Enter <a href=\"https://remix.run/\">Remix</a>.</p>\r\n<p>Remix is an interesting mix of old school techniques along with modern technology. Ryan Florence actually sums it up perfectly as to where Remix fits in.</p>\r\n<blockquote class=\"twitter-tweet\" data-dnt=\"true\" data-theme=\"dark\"><p lang=\"en\" dir=\"ltr\">Forget “full stack”. Remix is center stack.<br><br>It’s an HTTP tunnel between interactivity and business logic. It’s the part of the stack that no tool before it has solved, not completely.<br><br>I think I finally know how to talk about Remix.</p>— Ryan Florence (@ryanflorence) <a href=\"https://twitter.com/ryanflorence/status/1482233495195770883?ref_src=twsrc%5Etfw\">January 15, 2022</a></blockquote>\r\n<script async=\"\" src=\"https://platform.twitter.com/widgets.js\" charset=\"utf-8\"></script>\r\n<p>I was able to easily switch my site that was fully powered by Craft to utilize Craft only as a GraphQL endpoint and Remix powering the rest. The two big things I needed to figure out were: how to get data from the GraphQL endpoint, and then how to process input from a user (for my contact form). I would definitely recommend reading through the Remix docs and the two tutorials, but if you can understand these two big pictures things, you’ll have enough to get started with Remix and go deeper once you get into it.</p>\r\n<h2>Getting GraphQL Data (aka Loaders)</h2>\r\n<p>Remix provides a <a href=\"https://remix.run/docs/en/v1/api/conventions#loader\">loader hook</a> that runs on the server to hydrate your component. In this simple example, I run a GraphQL request and return JSON with the results of that request in the loader function.</p>'),(395,2949,1,'2023-01-27 14:50:36','2023-01-27 14:50:36','4fc78301-513f-40b8-b25a-17c2da7d8e47','import { GraphQLClient } from \'graphql-request\'\nimport { gql } from \'graphql-request\'\nimport { useLoaderData, json } from \'remix\'\n\nconst endpoint = \'https://your-endpoint-here/\'\nconst options = {\n    headers: {\n        authorization: \'Bearer YOUR_AUTH_TOKEN_HERE\',\n    }\n}\n\nconst EntriesQuery = gql`\n    {\n        YOUR GRAPHQL QUERY HERE\n    }\n`\n\nexport const loader = async () => {\n    const { entries } = new GraphQLClient(endpoint, options).request(EntriesQuery)\n\n    return json({\n        entries\n    })\n}\n\nexport default function Index() {\n    const data = useLoaderData()\n\n    return (\n        <>\n            {data.entries.map((entry) => (\n                <div key={entry.id}>\n                    {entry.title}\n                </div>\n            ))}\n        </>\n    )\n}','jsx',NULL),(396,2950,1,'2023-01-27 14:50:36','2023-01-27 14:50:36','2b5090f0-b1c2-430c-bdeb-7f5b4d2e1530',NULL,NULL,'<p>Then in my <code>Index</code> component, I access the data from the loader hook with <a href=\"https://remix.run/docs/en/v1/api/remix#useloaderdata\">useLoaderData()</a>, and my component is now hydrated with that data. In MVC style of thinking, think of the loader hook as the controller processing the page load request, populating with data from the model, and then passing to the view.</p>\r\n<p>The great part about Remix is that this doesn’t have to be specifically a GraphQL request. This data can come from anywhere. The <a href=\"https://remix.run/docs/en/v1/tutorials/jokes\">Jokes tutorial</a> in the Remix docs even thoroughly walks through how you can manage all this data in <a href=\"https://www.prisma.io/\">Prisma</a>.</p>\r\n<h2>Processing User Input (aka Actions)</h2>\r\n<p>Ok great, so we’ve got data onto the page, but now we need to be able to handle user input. Remix also provides an <a href=\"https://remix.run/docs/en/v1/api/conventions#action\">action hook</a> to process an action request (ex: a form submission). In my case, I have a contact form that sends me an email via SendGrid after submission.</p>'),(397,2951,1,'2023-01-27 14:50:36','2023-01-27 14:50:36','83b8798c-bfec-4533-ad37-ec29161e0d70','import {\n    useActionData,\n    Form,\n    redirect,\n    json\n} from \'remix\'\n\nexport async function action({ request }) {\n    const formData = await request.formData()\n    const errors = {}\n    \n    // Do data validation and add to the errors object if there are any errors\n    \n    if (Object.keys(errors).length) {\n        return json(errors, { status: 422 })\n    }\n    \n    // No errors: send email, store in DB, do whatever you need to do with the form data\n    \n    return redirect(\'/contact/thanks\')\n}\n\nexport default function ContactIndex() {\n    const errors = useActionData()\n    \n    return (\n        <Form method=\"post\">\n        </Form>\n    )\n}','jsx',NULL),(398,2952,1,'2023-01-27 14:50:36','2023-01-27 14:50:36','a90a62d5-bfdf-441b-a824-b4d7ac1eb482',NULL,NULL,'<p>If you don’t include an <code>action</code> attribute on your form, it will automatically submit to the same page. Again, in MVC thinking, the action would again be equivalent to the controller taking the request input and processing it. But honestly, this takes me back 15 years when form actions would point directly to PHP files.</p>\r\n<h2>Bonus: Progressive Enhancement</h2>\r\n<p>Since Remix is running on the server, you can turn off JavaScript and everything still works great. Data still loads, form actions still process; it’s beautiful. This is not running loaders and actions on the client side; it’s running them on the server. This isn’t an accident, the Remix team is carefully considering the UX.</p>\r\n<blockquote class=\"twitter-tweet\" data-dnt=\"true\" data-theme=\"dark\"><p lang=\"en\" dir=\"ltr\">User experience (UX) and developer experience (DX) are both important. UX is more important than DX.<a href=\"https://twitter.com/remix_run?ref_src=twsrc%5Etfw\">@remix_run</a> has taught me: It\'s easier to start with a great UX and work toward a good DX than it is to start with a great DX and work toward a good UX.</p>— Kent C. Dodds &#x1f4bf; (@kentcdodds) <a href=\"https://twitter.com/kentcdodds/status/1482390454389805058?ref_src=twsrc%5Etfw\">January 15, 2022</a></blockquote>\r\n<script async=\"\" src=\"https://platform.twitter.com/widgets.js\" charset=\"utf-8\"></script>\r\n<h2>Bonus: So Speedy</h2>\r\n<p>Did I mention how fast everything renders? I don’t tend to put too much stock into Lighthouse scores since they seem so random, but Remix crushes Lighthouse without me having to invest any additional effort into improving performance.</p>\r\n<h2>Give it a Shot</h2>\r\n<p>Remix is built on the <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API\">native Fetch API</a>, so it can run anywhere. While Remix is relatively new, it’s certainly production ready, and there is a dedicated team behind it. If you aren’t ready to dive into Remix yet, at least keep your eye on it because this is a game changer.</p>'),(399,2954,1,'2023-02-15 21:55:51','2023-02-15 21:55:51','57577da1-0b58-4dec-b193-733e169937d2',NULL,NULL,'<p>I’ve been building on the web for a long time. There’s a part of me that still has a bit of an old school mentality, and it’s hard for me to get really excited about new technology. Sure React was cool when it came out for its state management, but I didn’t see it as the be-all and end-all for building on the web. I really like <a href=\"https://craftcms.com/\">Craft CMS</a> for building CMS powered sites since I have full control over the HTML being sent to the browser, and it’s really easy to extend for complex functionality, but it can be a bit complex to setup for beginners and with additional complexity can come performance issues.&nbsp;So it’s been a while since I’ve seen something to be <em>really</em> excited about.</p>\r\n<p>Enter <a href=\"https://remix.run/\">Remix</a>.</p>\r\n<p>Remix is an interesting mix of old school techniques along with modern technology. Ryan Florence actually sums it up perfectly as to where Remix fits in.</p>\r\n<blockquote class=\"twitter-tweet\" data-dnt=\"true\" data-theme=\"dark\"><p lang=\"en\" dir=\"ltr\">Forget “full stack”. Remix is center stack.<br><br>It’s an HTTP tunnel between interactivity and business logic. It’s the part of the stack that no tool before it has solved, not completely.<br><br>I think I finally know how to talk about Remix.</p>— Ryan Florence (@ryanflorence) <a href=\"https://twitter.com/ryanflorence/status/1482233495195770883?ref_src=twsrc%5Etfw\">January 15, 2022</a></blockquote>\r\n<script async=\"\" src=\"https://platform.twitter.com/widgets.js\" charset=\"utf-8\"></script>\r\n<p>I was able to easily switch my site that was fully powered by Craft to utilize Craft only as a GraphQL endpoint and Remix powering the rest. The two big things I needed to figure out were: how to get data from the GraphQL endpoint, and then how to process input from a user (for my contact form). I would definitely recommend reading through the Remix docs and the two tutorials, but if you can understand these two big pictures things, you’ll have enough to get started with Remix and go deeper once you get into it.</p>\r\n<h2>Getting GraphQL Data (aka Loaders)</h2>\r\n<p>Remix provides a <a href=\"https://remix.run/docs/en/v1/api/conventions#loader\">loader hook</a> that runs on the server to hydrate your component. In this simple example, I run a GraphQL request and return JSON with the results of that request in the loader function.</p>'),(400,2955,1,'2023-02-15 21:55:51','2023-02-15 21:55:51','6b7e33d1-420f-413c-a223-80ab05b73cff','import { GraphQLClient } from \'graphql-request\'\nimport { gql } from \'graphql-request\'\nimport { useLoaderData, json } from \'remix\'\n\nconst endpoint = \'https://your-endpoint-here/\'\nconst options = {\n    headers: {\n        authorization: \'Bearer YOUR_AUTH_TOKEN_HERE\',\n    }\n}\n\nconst EntriesQuery = gql`\n    {\n        YOUR GRAPHQL QUERY HERE\n    }\n`\n\nexport const loader = async () => {\n    const { entries } = new GraphQLClient(endpoint, options).request(EntriesQuery)\n\n    return json({\n        entries\n    })\n}\n\nexport default function Index() {\n    const data = useLoaderData()\n\n    return (\n        <>\n            {data.entries.map((entry) => (\n                <div key={entry.id}>\n                    {entry.title}\n                </div>\n            ))}\n        </>\n    )\n}','jsx',NULL),(401,2956,1,'2023-02-15 21:55:51','2023-02-15 21:55:51','c206e43b-5a51-4ab3-b244-6235480754ca',NULL,NULL,'<p>Then in my <code>Index</code> component, I access the data from the loader hook with <a href=\"https://remix.run/docs/en/v1/api/remix#useloaderdata\">useLoaderData()</a>, and my component is now hydrated with that data. In MVC style of thinking, think of the loader hook as the controller processing the page load request, populating with data from the model, and then passing to the view.</p>\r\n<p>The great part about Remix is that this doesn’t have to be specifically a GraphQL request. This data can come from anywhere. The <a href=\"https://remix.run/docs/en/v1/tutorials/jokes\">Jokes tutorial</a> in the Remix docs even thoroughly walks through how you can manage all this data in <a href=\"https://www.prisma.io/\">Prisma</a>.</p>\r\n<h2>Processing User Input (aka Actions)</h2>\r\n<p>Ok great, so we’ve got data onto the page, but now we need to be able to handle user input. Remix also provides an <a href=\"https://remix.run/docs/en/v1/api/conventions#action\">action hook</a> to process an action request (ex: a form submission). In my case, I have a contact form that sends me an email via SendGrid after submission.</p>'),(402,2957,1,'2023-02-15 21:55:51','2023-02-15 21:55:51','e46d52fc-f6c0-452a-938c-071484b35ea0','import {\n    useActionData,\n    Form,\n    redirect,\n    json\n} from \'remix\'\n\nexport async function action({ request }) {\n    const formData = await request.formData()\n    const errors = {}\n    \n    // Do data validation and add to the errors object if there are any errors\n    \n    if (Object.keys(errors).length) {\n        return json(errors, { status: 422 })\n    }\n    \n    // No errors: send email, store in DB, do whatever you need to do with the form data\n    \n    return redirect(\'/contact/thanks\')\n}\n\nexport default function ContactIndex() {\n    const errors = useActionData()\n    \n    return (\n        <Form method=\"post\">\n        </Form>\n    )\n}','jsx',NULL),(403,2958,1,'2023-02-15 21:55:51','2023-02-15 21:55:51','ce741c80-4fd1-461d-83f6-a8f06858bfec',NULL,NULL,'<p>If you don’t include an <code>action</code> attribute on your form, it will automatically submit to the same page. Again, in MVC thinking, the action would again be equivalent to the controller taking the request input and processing it. But honestly, this takes me back 15 years when form actions would point directly to PHP files.</p>\r\n<h2>Bonus: Progressive Enhancement</h2>\r\n<p>Since Remix is running on the server, you can turn off JavaScript and everything still works great. Data still loads, form actions still process; it’s beautiful. This is not running loaders and actions on the client side; it’s running them on the server. This isn’t an accident, the Remix team is carefully considering the UX.</p>\r\n<blockquote class=\"twitter-tweet\" data-dnt=\"true\" data-theme=\"dark\"><p lang=\"en\" dir=\"ltr\">User experience (UX) and developer experience (DX) are both important. UX is more important than DX.<a href=\"https://twitter.com/remix_run?ref_src=twsrc%5Etfw\">@remix_run</a> has taught me: It\'s easier to start with a great UX and work toward a good DX than it is to start with a great DX and work toward a good UX.</p>— Kent C. Dodds &#x1f4bf; (@kentcdodds) <a href=\"https://twitter.com/kentcdodds/status/1482390454389805058?ref_src=twsrc%5Etfw\">January 15, 2022</a></blockquote>\r\n<script async=\"\" src=\"https://platform.twitter.com/widgets.js\" charset=\"utf-8\"></script>\r\n<h2>Bonus: So Speedy</h2>\r\n<p>Did I mention how fast everything renders? I don’t tend to put too much stock into Lighthouse scores since they seem so random, but Remix crushes Lighthouse without me having to invest any additional effort into improving performance.</p>\r\n<h2>Give it a Shot</h2>\r\n<p>Remix is built on the <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API\">native Fetch API</a>, so it can run anywhere. While Remix is relatively new, it’s certainly production ready, and there is a dedicated team behind it. If you aren’t ready to dive into Remix yet, at least keep your eye on it because this is a game changer.</p>'),(1097,4176,1,'2024-06-17 21:12:06','2024-06-17 21:12:06','f3024e4e-b038-4ddf-841b-5f61b96a0e77',NULL,NULL,'<p>In my <a href=\"https://www.trevor-davis.com/blog/why-im-so-excited-about-remix\">previous post</a>, I talked about transitioning my site from being powered by <a href=\"https://craftcms.com/\">Craft</a> to being powered by <a href=\"https://remix.run/\">Remix</a> and a GraphQL endpoint coming from Craft. One of the best features of Craft is <a href=\"https://craftcms.com/features/all#live-preview\">Live Preview</a>, and it took a little configuration to get this working on my new Remix powered site.</p>\r\n<h2>Remix Configuration</h2>\r\n<p>These were specific changes that I needed to make on the Remix side, but really it would be the same for any GraphQL request. As Andrew Welch breaks down in <a href=\"https://nystudio107.com/blog/headless-preview-in-craft-cms\">his article</a>, the key is passing the token parameter back that Craft included in the URL.</p>\r\n<p>In the loader function of my blog post route, I call a helper function to setup the GraphQL client, and I pass the request to it:</p>'),(1098,4177,1,'2024-06-17 21:12:06','2024-06-17 21:12:06','159b3849-963a-4490-bd0b-5b7ac39f32c3','import { json } from \'remix\'\nimport { gql } from \'graphql-request\'\nimport { gqlClient } from \'graphql.server\'\n\nexport const loader = async ({ request }) => {\n    const { entries } = await gqlClient(request).request(gql`\n        {\n            YOUR GRAPHQL QUERY HERE\n        }\n    `)\n\n    return json({ entries })\n}','jsx',NULL),(1099,4178,1,'2024-06-17 21:12:06','2024-06-17 21:12:06','14357008-6e2c-47c8-8e46-4f257fba079c',NULL,NULL,'<p>And then in my helper function, I take that request, grab the URL params that I want to include, and add those to my GraphQL request endpoint URL:</p>'),(1100,4179,1,'2024-06-17 21:12:07','2024-06-17 21:12:07','2eb22d0b-3aab-45c8-897d-790c137047f8','import { GraphQLClient } from \'graphql-request\'\n\n// Extract allowed query params and construct query string\nconst getQueryParams = (request) => {\n    const url = new URL(request.url)\n    const allowedKeys = [\'x-craft-preview\', \'x-craft-live-preview\', \'token\']\n    const filteredParams = Object.entries(\n        Object.fromEntries(url.searchParams)\n    ).filter(([key]) => allowedKeys.includes(key))\n\n    if (!filteredParams.length) {\n        return \'\'\n    }\n\n    const queryString = filteredParams.map((val) => val.join(\'=\')).join(\'&\')\n\n    return `?${queryString}`\n}\n\nexport const gqlClient = (request = null) => {\n    const queryString = request ? getQueryParams(request) : \'\'\n\n    return new GraphQLClient(`https://your-endpoint-here/${queryString}`, {\n        headers: {\n            authorization: `Bearer YOUR_AUTH_TOKEN_HERE`,\n        },\n    })\n}','jsx',NULL),(1101,4180,1,'2024-06-17 21:12:07','2024-06-17 21:12:07','f7ab94c9-ba8a-4f0c-ae45-2dedd81037a4',NULL,NULL,'<p>It wasn’t totally necessary to include the <code>x-craft-preview</code> and <code>x-craft-live-preview</code> parameters, but I figured it couldn’t hurt.</p>\r\n<h2>Craft Configuration</h2>\r\n<p>Now with the Remix configuration in place, I just needed to make two small changes to Craft to get it working correctly. First, I had to update the preview target for my Blog section to point to my Remix site:</p>\r\n<figure><img src=\"{asset:2283:url||//assets.trevor-davis.com/uploads/images/content/blog-section-preview-target.png}\" data-image=\"2283\" alt=\"Setting the preview target in my Blog Section\"></figure>\r\n<p>Then, I had to update the <code>config/general.php</code> to allow iframe requests from my Remix domain:</p>'),(1102,4181,1,'2024-06-17 21:12:07','2024-06-17 21:12:07','75c25801-1cf8-4e13-9f6c-f5685f18c873','<?php\n\nreturn [\n    \'*\' => [\n        \'headlessMode\' => true,\n        \'previewIframeResizerOptions\' => [\n            \'checkOrigin\' => [\n                \'https://www.trevor-davis.com\',\n            ],\n        ],\n    ],\n];','php',NULL),(1103,4182,1,'2024-06-17 21:12:07','2024-06-17 21:12:07','fb26161a-3778-4f3a-a03e-67d45687dfc7',NULL,NULL,'<h2>Voilà, Live Preview</h2>\r\n<p>And just like that, I had live preview working.</p>\r\n<p><video src=\"{asset:2299:url||//assets.trevor-davis.com/uploads/images/content/live-preview.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\" width=\"100%\"></video></p>'),(1209,4304,1,'2024-07-29 14:35:24','2024-07-29 14:35:24','0089f2a0-4f06-49ac-87e2-4b3fbdd57591',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1210,4305,1,'2024-07-29 14:35:24','2024-07-29 14:35:24','dcc2b0e0-ab91-4e4a-80ed-337a7d56b661','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1211,4306,1,'2024-07-29 14:35:24','2024-07-29 14:35:24','c6019e11-2026-4e52-9ec9-c39a75012540',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1212,4307,1,'2024-07-29 14:35:24','2024-07-29 14:35:24','149eab15-3764-40f6-a821-acf54602a824','ReferenceError: window is not defined','text',NULL),(1213,4308,1,'2024-07-29 14:35:24','2024-07-29 14:35:24','f5c61719-4b3d-4b72-8fe3-0faed8b4c961',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1214,4309,1,'2024-07-29 14:35:24','2024-07-29 14:35:24','d614c3ea-b573-4b96-b275-cb1cc799b6d5','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1215,4310,1,'2024-07-29 14:35:24','2024-07-29 14:35:24','4899e8b1-1b8d-4119-bdf8-90d6540e0607',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1216,4312,1,'2024-07-29 14:35:25','2024-07-29 14:35:25','e537ade1-2625-4ab6-a664-221d981442b2',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1217,4313,1,'2024-07-29 14:35:25','2024-07-29 14:35:25','7ba54b28-1a51-42f1-a6a9-828d581b8377','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1218,4314,1,'2024-07-29 14:35:25','2024-07-29 14:35:25','dfb0d6f6-2043-4060-b3fb-05091cab6dde',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1219,4315,1,'2024-07-29 14:35:25','2024-07-29 14:35:25','90b0fcd0-23c8-450b-a9f2-a12922f1d8bb','ReferenceError: window is not defined','text',NULL),(1220,4316,1,'2024-07-29 14:35:25','2024-07-29 14:35:25','ce34a8a2-05cb-45ca-8c42-38583d60befa',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1221,4317,1,'2024-07-29 14:35:25','2024-07-29 14:35:25','3d94d708-fb0f-46ef-bc04-df296bc8256d','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1222,4318,1,'2024-07-29 14:35:25','2024-07-29 14:35:25','31efaa10-11b2-45c7-9de8-7211c6470353',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1223,4320,1,'2024-07-29 14:35:28','2024-07-29 14:35:28','164946e3-59e9-4d0a-95de-7ed68ae88aa4',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1224,4321,1,'2024-07-29 14:35:28','2024-07-29 14:35:28','71a83875-c238-4b8c-8eb5-37dae9841841','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1225,4322,1,'2024-07-29 14:35:28','2024-07-29 14:35:28','1e1d1de0-f016-4c3d-a176-361847c44cf4',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1226,4323,1,'2024-07-29 14:35:28','2024-07-29 14:35:28','234b61aa-42a7-411c-b15d-b5706a8f5c25','ReferenceError: window is not defined','text',NULL),(1227,4324,1,'2024-07-29 14:35:28','2024-07-29 14:35:28','091259bd-cd07-4e7b-a8c6-938c0f4d7c69',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1228,4325,1,'2024-07-29 14:35:28','2024-07-29 14:35:28','6ffde1e8-7b3a-4fe4-b224-0909b38d54db','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1229,4326,1,'2024-07-29 14:35:28','2024-07-29 14:35:28','b6a4b86f-f752-4f71-87aa-d134faf302f5',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1230,4328,1,'2024-07-29 14:35:29','2024-07-29 14:35:29','6914456e-b82b-43c1-8948-4dda8a93a074',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1231,4329,1,'2024-07-29 14:35:29','2024-07-29 14:35:29','8fa49037-739b-4302-a048-cdb4e48ba25a','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1232,4330,1,'2024-07-29 14:35:29','2024-07-29 14:35:29','a40edaf1-912b-4dbc-8597-d15dec8502d6',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1233,4331,1,'2024-07-29 14:35:29','2024-07-29 14:35:29','751acec3-eecb-40f6-8136-b8c4b148013d','ReferenceError: window is not defined','text',NULL),(1234,4332,1,'2024-07-29 14:35:29','2024-07-29 14:35:29','0cf58f90-78c0-4bb9-892d-00a737671426',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1235,4333,1,'2024-07-29 14:35:29','2024-07-29 14:35:29','95253e1a-3611-43f1-832a-f431d8d2a2c6','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1236,4334,1,'2024-07-29 14:35:29','2024-07-29 14:35:29','7dff117c-50d1-4d23-abfb-70886591a5df',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1237,4336,1,'2024-07-29 14:35:30','2024-07-29 14:35:30','54af83f7-9ba7-4c27-bb3e-0867ff173075',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1238,4337,1,'2024-07-29 14:35:30','2024-07-29 14:35:30','dbe7d2d8-973b-4ad4-95a1-2dfa4ebddc3b','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1239,4338,1,'2024-07-29 14:35:30','2024-07-29 14:35:30','7fa8cfc6-728e-4389-a267-ae4682f9e425',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1240,4339,1,'2024-07-29 14:35:30','2024-07-29 14:35:30','d1b2aeb1-db92-4fa9-9624-c1002866b984','ReferenceError: window is not defined','text',NULL),(1241,4340,1,'2024-07-29 14:35:30','2024-07-29 14:35:30','efaa2172-815f-4fb5-b64f-ba138d4c1e8b',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1242,4341,1,'2024-07-29 14:35:30','2024-07-29 14:35:30','1dd61b3f-2e5c-4d65-b26a-c5ac91ee9b5a','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1243,4342,1,'2024-07-29 14:35:30','2024-07-29 14:35:30','cf75f06d-89b7-4c34-a849-05dff6da9216',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1244,4362,1,'2024-09-12 10:20:05','2024-09-12 10:20:05','c060523d-d129-40a1-a3cf-35ef2563286d',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1245,4363,1,'2024-09-12 10:20:05','2024-09-12 10:20:05','6d39d87d-820c-4783-9da6-2199745682cf','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1246,4364,1,'2024-09-12 10:20:05','2024-09-12 10:20:05','ed88f986-7e0f-42cc-bd34-1b9ab6937ce6',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1247,4365,1,'2024-09-12 10:20:05','2024-09-12 10:20:05','feb3d965-d099-433d-b180-857d36b5815e','ReferenceError: window is not defined','text',NULL),(1248,4366,1,'2024-09-12 10:20:05','2024-09-12 10:20:05','cb109c13-f3e1-4264-8dd8-8b42c72aa164',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1249,4367,1,'2024-09-12 10:20:05','2024-09-12 10:20:05','298d91be-d32e-4713-851b-d4dafa9e20f1','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1250,4368,1,'2024-09-12 10:20:05','2024-09-12 10:20:05','45a2957d-6f89-40d0-a712-424188ec072d',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1251,4370,1,'2024-09-12 10:20:06','2024-09-12 10:20:06','a1d958e0-f0c7-44bd-918e-bd2e3b68f227',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1252,4371,1,'2024-09-12 10:20:06','2024-09-12 10:20:06','fbc1ca98-a83e-424b-941d-60e2fdb74cdc','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1253,4372,1,'2024-09-12 10:20:06','2024-09-12 10:20:06','06cd838e-3f61-464d-b449-7840eb12de41',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1254,4373,1,'2024-09-12 10:20:06','2024-09-12 10:20:06','68455d26-b0c4-40b9-89d7-1df865fba879','ReferenceError: window is not defined','text',NULL),(1255,4374,1,'2024-09-12 10:20:06','2024-09-12 10:20:06','58101f54-e0dd-4064-b1ce-8c64359fa3bc',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1256,4375,1,'2024-09-12 10:20:06','2024-09-12 10:20:06','3288e22f-434d-4403-a9b9-8851c03093be','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1257,4376,1,'2024-09-12 10:20:06','2024-09-12 10:20:06','e327d3b1-7594-496c-9fdf-8b574e0fbc85',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1258,4378,1,'2024-09-12 10:20:08','2024-09-12 10:20:08','a60cfc9b-3930-4036-b141-58d1e135d26d',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1259,4379,1,'2024-09-12 10:20:08','2024-09-12 10:20:08','b0be847d-ed16-4c0e-affb-5329febd111f','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1260,4380,1,'2024-09-12 10:20:08','2024-09-12 10:20:08','8903773a-ccbb-4a86-af5d-244099542abe',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1261,4381,1,'2024-09-12 10:20:08','2024-09-12 10:20:08','cee5a90d-0ff7-47fb-b459-91a5e22df5d6','ReferenceError: window is not defined','text',NULL),(1262,4382,1,'2024-09-12 10:20:08','2024-09-12 10:20:08','a53be516-a096-4a86-974c-3959bc2ebd58',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1263,4383,1,'2024-09-12 10:20:08','2024-09-12 10:20:08','0a258fad-2b76-4fad-9c60-8605cb1cecb2','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1264,4384,1,'2024-09-12 10:20:08','2024-09-12 10:20:08','c3d1dd2d-b2f9-4163-80d2-747bdd3672cb',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1265,4386,1,'2024-09-19 09:44:11','2024-09-19 09:44:11','89dda878-0e6b-4ea0-9394-b3e082a762cd',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1266,4387,1,'2024-09-19 09:44:11','2024-09-19 09:44:11','4f30e2fd-1fd8-4fc0-ae4c-07ff7477890c','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1267,4388,1,'2024-09-19 09:44:11','2024-09-19 09:44:11','1eba5759-8233-4827-a8b8-b33f49a53265',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1268,4389,1,'2024-09-19 09:44:11','2024-09-19 09:44:11','af8b54c2-5526-4b7d-9b2d-5748eb3db504','ReferenceError: window is not defined','text',NULL),(1269,4390,1,'2024-09-19 09:44:11','2024-09-19 09:44:11','3cd088f3-e08b-42ae-a42d-143a19e5773f',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1270,4391,1,'2024-09-19 09:44:11','2024-09-19 09:44:11','0960abdd-29e7-4d37-960a-41da9e13dbe2','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1271,4392,1,'2024-09-19 09:44:11','2024-09-19 09:44:11','fe653ad2-a230-4d75-a29d-fb6a39a53f06',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1272,4394,1,'2024-09-19 09:44:13','2024-09-19 09:44:13','5c6650e6-a698-4c09-a468-db33445e9fe4',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1273,4395,1,'2024-09-19 09:44:13','2024-09-19 09:44:13','f9947448-eebd-4936-b446-4ffe912d386b','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1274,4396,1,'2024-09-19 09:44:13','2024-09-19 09:44:13','94f16134-f5d7-425c-bde7-e52685b3bcb2',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1275,4397,1,'2024-09-19 09:44:13','2024-09-19 09:44:13','af857284-1d3b-4864-99d7-35873b35e10d','ReferenceError: window is not defined','text',NULL),(1276,4398,1,'2024-09-19 09:44:13','2024-09-19 09:44:13','fd94c71d-1a95-41ab-a26c-f70b41ba8374',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1277,4399,1,'2024-09-19 09:44:13','2024-09-19 09:44:13','49459e93-164f-42f8-b736-29f661a16fd7','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1278,4400,1,'2024-09-19 09:44:13','2024-09-19 09:44:13','d7292f78-2e41-45fd-9d52-726831b3f593',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1279,4402,1,'2024-09-19 09:44:14','2024-09-19 09:44:14','19a2979f-62c4-4b90-b898-0ffdaec1663a',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1280,4403,1,'2024-09-19 09:44:14','2024-09-19 09:44:14','400daba0-8d97-460e-8b11-8e544453f781','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1281,4404,1,'2024-09-19 09:44:14','2024-09-19 09:44:14','2b676dca-5d9a-4e96-8c39-c8ca9fccf41e',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1282,4405,1,'2024-09-19 09:44:14','2024-09-19 09:44:14','35381e1e-d4ba-4d91-a2d5-c83519b4c9a5','ReferenceError: window is not defined','text',NULL),(1283,4406,1,'2024-09-19 09:44:14','2024-09-19 09:44:14','80d366ed-6ec8-40aa-97c0-c972b2dad0fd',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1284,4407,1,'2024-09-19 09:44:14','2024-09-19 09:44:14','167af30f-909e-4900-8d68-5d215b7aa9d8','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1285,4408,1,'2024-09-19 09:44:14','2024-09-19 09:44:14','3a6ad193-5929-4313-b82a-9d1eaee1ad42',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1286,4410,1,'2024-10-09 09:59:48','2024-10-09 09:59:48','a8a0ca95-d0b5-4b42-b5d8-fc6b36e1cdd7',NULL,NULL,'<p>In my <a href=\"https://www.trevor-davis.com/blog/why-im-so-excited-about-remix\">previous post</a>, I talked about transitioning my site from being powered by <a href=\"https://craftcms.com/\">Craft</a> to being powered by <a href=\"https://remix.run/\">Remix</a> and a GraphQL endpoint coming from Craft. One of the best features of Craft is <a href=\"https://craftcms.com/features/all#live-preview\">Live Preview</a>, and it took a little configuration to get this working on my new Remix powered site.</p>\r\n<h2>Remix Configuration</h2>\r\n<p>These were specific changes that I needed to make on the Remix side, but really it would be the same for any GraphQL request. As Andrew Welch breaks down in <a href=\"https://nystudio107.com/blog/headless-preview-in-craft-cms\">his article</a>, the key is passing the token parameter back that Craft included in the URL.</p>\r\n<p>In the loader function of my blog post route, I call a helper function to setup the GraphQL client, and I pass the request to it:</p>'),(1287,4411,1,'2024-10-09 09:59:48','2024-10-09 09:59:48','bc612d21-1f02-4bf7-be8d-ca4e8e4742b9','import { json } from \'remix\'\nimport { gql } from \'graphql-request\'\nimport { gqlClient } from \'graphql.server\'\n\nexport const loader = async ({ request }) => {\n    const { entries } = await gqlClient(request).request(gql`\n        {\n            YOUR GRAPHQL QUERY HERE\n        }\n    `)\n\n    return json({ entries })\n}','jsx',NULL),(1288,4412,1,'2024-10-09 09:59:48','2024-10-09 09:59:48','d05fdf70-8f1d-46a0-b708-4bc0febbf41b',NULL,NULL,'<p>And then in my helper function, I take that request, grab the URL params that I want to include, and add those to my GraphQL request endpoint URL:</p>'),(1289,4413,1,'2024-10-09 09:59:48','2024-10-09 09:59:48','d23aa81d-0099-441e-afe8-f7280253df0b','import { GraphQLClient } from \'graphql-request\'\n\n// Extract allowed query params and construct query string\nconst getQueryParams = (request) => {\n    const url = new URL(request.url)\n    const allowedKeys = [\'x-craft-preview\', \'x-craft-live-preview\', \'token\']\n    const filteredParams = Object.entries(\n        Object.fromEntries(url.searchParams)\n    ).filter(([key]) => allowedKeys.includes(key))\n\n    if (!filteredParams.length) {\n        return \'\'\n    }\n\n    const queryString = filteredParams.map((val) => val.join(\'=\')).join(\'&\')\n\n    return `?${queryString}`\n}\n\nexport const gqlClient = (request = null) => {\n    const queryString = request ? getQueryParams(request) : \'\'\n\n    return new GraphQLClient(`https://your-endpoint-here/${queryString}`, {\n        headers: {\n            authorization: `Bearer YOUR_AUTH_TOKEN_HERE`,\n        },\n    })\n}','jsx',NULL),(1290,4414,1,'2024-10-09 09:59:48','2024-10-09 09:59:48','391d3ee1-37d4-4891-ac1c-967c0e219607',NULL,NULL,'<p>It wasn’t totally necessary to include the <code>x-craft-preview</code> and <code>x-craft-live-preview</code> parameters, but I figured it couldn’t hurt.</p>\r\n<h2>Craft Configuration</h2>\r\n<p>Now with the Remix configuration in place, I just needed to make two small changes to Craft to get it working correctly. First, I had to update the preview target for my Blog section to point to my Remix site:</p>\r\n<figure><img src=\"{asset:2283:url||//assets.trevor-davis.com/uploads/images/content/blog-section-preview-target.png}\" data-image=\"2283\" alt=\"Setting the preview target in my Blog Section\"></figure>\r\n<p>Then, I had to update the <code>config/general.php</code> to allow iframe requests from my Remix domain:</p>'),(1291,4415,1,'2024-10-09 09:59:48','2024-10-09 09:59:48','04dcbcb3-09ca-42a5-9e70-f07ca0d1da01','<?php\n\nreturn [\n    \'*\' => [\n        \'headlessMode\' => true,\n        \'previewIframeResizerOptions\' => [\n            \'checkOrigin\' => [\n                \'https://www.trevor-davis.com\',\n            ],\n        ],\n    ],\n];','php',NULL),(1292,4416,1,'2024-10-09 09:59:48','2024-10-09 09:59:48','40fcea32-212f-450c-8387-3ecb77ccda35',NULL,NULL,'<h2>Voilà, Live Preview</h2>\r\n<p>And just like that, I had live preview working.</p>\r\n<p><video src=\"{asset:2299:url||//assets.trevor-davis.com/uploads/images/content/live-preview.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\" width=\"100%\"></video></p>'),(1293,4418,1,'2024-10-09 13:00:49','2024-10-09 13:00:49','2d05551a-3857-47c3-ac78-0fc1206297e9',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1294,4419,1,'2024-10-09 13:00:49','2024-10-09 13:00:49','17b9e5b7-ee2e-401f-9867-675c1ccfab30','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1295,4420,1,'2024-10-09 13:00:49','2024-10-09 13:00:49','97f22e2c-d914-4123-a3a0-c782cae8061f',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1296,4421,1,'2024-10-09 13:00:49','2024-10-09 13:00:49','ea96827c-0913-4002-95dc-9b3aa154f8f3','ReferenceError: window is not defined','text',NULL),(1297,4422,1,'2024-10-09 13:00:49','2024-10-09 13:00:49','f85f50a8-d1b9-4c65-b021-24506c4a5f4a',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1298,4423,1,'2024-10-09 13:00:49','2024-10-09 13:00:49','1d9b992b-e3c8-4729-af42-eb3f086ccb9f','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1299,4424,1,'2024-10-09 13:00:49','2024-10-09 13:00:49','59e03442-a30f-434d-a0be-ced69cd0d0c1',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1300,4426,1,'2024-10-09 13:00:50','2024-10-09 13:00:50','e1c0743f-99fc-463f-95b0-7b2b2bb86b00',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1301,4427,1,'2024-10-09 13:00:50','2024-10-09 13:00:50','a52fd4dd-0b96-45a9-8490-ca3a17b5f5e8','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1302,4428,1,'2024-10-09 13:00:50','2024-10-09 13:00:50','bec27cfc-4f16-4f7a-9403-2a8d0778ce11',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1303,4429,1,'2024-10-09 13:00:50','2024-10-09 13:00:50','1e7053a9-0163-4f71-8b22-bbc8e8c3033e','ReferenceError: window is not defined','text',NULL),(1304,4430,1,'2024-10-09 13:00:50','2024-10-09 13:00:50','6f9f377d-ef7b-4260-8b46-744b1b3c1d77',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1305,4431,1,'2024-10-09 13:00:50','2024-10-09 13:00:50','4388b63b-a5fa-40b6-af81-9ded198ff366','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1306,4432,1,'2024-10-09 13:00:50','2024-10-09 13:00:50','a19c5bb4-7c20-4e76-9ec7-16e850a8c1fd',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1307,4434,1,'2024-10-11 07:54:50','2024-10-11 07:54:50','bd1b95c9-d35f-4ea6-ab22-4202359cc273',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1308,4435,1,'2024-10-11 07:54:50','2024-10-11 07:54:50','9ee8d22d-451a-48b2-befe-e54f662fbc5e','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1309,4436,1,'2024-10-11 07:54:50','2024-10-11 07:54:50','af91f397-7307-4f48-9c24-239345eb9a9c',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1310,4437,1,'2024-10-11 07:54:50','2024-10-11 07:54:50','0eb0175c-862c-4e83-89be-7ee588a7d696','ReferenceError: window is not defined','text',NULL),(1311,4438,1,'2024-10-11 07:54:50','2024-10-11 07:54:50','7ccd1c9c-a3e5-4600-9cc3-c52b744d2956',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1312,4439,1,'2024-10-11 07:54:50','2024-10-11 07:54:50','852c9fa3-c03d-443f-bb77-70ea8bc79020','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1313,4440,1,'2024-10-11 07:54:50','2024-10-11 07:54:50','15957ccb-67a5-462a-b7ec-e5774bdbf18a',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1314,4442,1,'2024-10-11 07:54:50','2024-10-11 07:54:50','09948bbc-50e3-41f4-95bc-061f6bf01f56',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1315,4443,1,'2024-10-11 07:54:50','2024-10-11 07:54:50','c20d74da-9a54-44fe-9942-f4ef10cfa698','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1316,4444,1,'2024-10-11 07:54:50','2024-10-11 07:54:50','ccf51831-5a8a-4459-89e8-cc6dc281b0ec',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1317,4445,1,'2024-10-11 07:54:50','2024-10-11 07:54:50','20aa223d-78f6-4dbc-959b-71e34aba6fcb','ReferenceError: window is not defined','text',NULL),(1318,4446,1,'2024-10-11 07:54:50','2024-10-11 07:54:50','0bde7958-7fbe-47e9-a22e-f4b5668b7968',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1319,4447,1,'2024-10-11 07:54:50','2024-10-11 07:54:50','b3a696fe-db61-4725-a658-975285b48098','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1320,4448,1,'2024-10-11 07:54:50','2024-10-11 07:54:50','9bc78e72-d803-4582-acbe-592492fcef9a',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1321,4450,1,'2024-10-11 07:54:52','2024-10-11 07:54:52','a0ccbf09-3c53-40fd-b1ad-81c3d82df220',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1322,4451,1,'2024-10-11 07:54:52','2024-10-11 07:54:52','21fb7838-4fe6-4a39-bc07-9b0707f82e6b','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1323,4452,1,'2024-10-11 07:54:52','2024-10-11 07:54:52','f3f19ce8-8e3e-4773-9d12-1e20cacbefa3',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1324,4453,1,'2024-10-11 07:54:52','2024-10-11 07:54:52','65c93053-2c40-44bc-9117-ba0a17590325','ReferenceError: window is not defined','text',NULL),(1325,4454,1,'2024-10-11 07:54:52','2024-10-11 07:54:52','6d8f3fe4-1f14-4442-9d31-c269bbe602a1',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1326,4455,1,'2024-10-11 07:54:52','2024-10-11 07:54:52','8893eb8c-025e-4832-a007-1e99431a06aa','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1327,4456,1,'2024-10-11 07:54:52','2024-10-11 07:54:52','1170dd20-d8f9-40ba-afa8-5a90cbcc180b',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1328,4458,1,'2024-10-11 07:54:56','2024-10-11 07:54:56','66cb605e-b85e-4232-895e-208257417a2d',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1329,4459,1,'2024-10-11 07:54:56','2024-10-11 07:54:56','f4f86176-2830-482f-be5e-f8d66ba7abe3','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1330,4460,1,'2024-10-11 07:54:56','2024-10-11 07:54:56','d87571dc-78c3-4fff-9842-40f85c0b713e',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1331,4461,1,'2024-10-11 07:54:56','2024-10-11 07:54:56','727a1535-5ad7-4138-b71a-f6a85aba1cc7','ReferenceError: window is not defined','text',NULL),(1332,4462,1,'2024-10-11 07:54:56','2024-10-11 07:54:56','240e7dbc-f1b9-458b-82f9-a03a29b2a361',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1333,4463,1,'2024-10-11 07:54:56','2024-10-11 07:54:56','a0adc4a3-485a-4844-b1dd-49e6912ae8c5','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1334,4464,1,'2024-10-11 07:54:56','2024-10-11 07:54:56','96b17ab8-2733-4939-b0ce-d593f86686cf',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1335,4466,1,'2024-10-22 03:57:21','2024-10-22 03:57:21','3694901b-90f2-4dbb-9f53-5c1a17133f94',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1336,4467,1,'2024-10-22 03:57:21','2024-10-22 03:57:21','523651d8-4185-4621-8394-9e78c6a547b0','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1337,4468,1,'2024-10-22 03:57:21','2024-10-22 03:57:21','2afa0a69-4cd4-42af-baa3-bc2277716943',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1338,4469,1,'2024-10-22 03:57:21','2024-10-22 03:57:21','f39c3814-d3c6-426f-8d73-23efa1b29607','ReferenceError: window is not defined','text',NULL),(1339,4470,1,'2024-10-22 03:57:21','2024-10-22 03:57:21','f0f2c5e5-eff6-4572-b97a-bf2b596d444b',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1340,4471,1,'2024-10-22 03:57:21','2024-10-22 03:57:21','d4ed7aa7-e907-4e65-90d8-9313d781f415','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1341,4472,1,'2024-10-22 03:57:21','2024-10-22 03:57:21','0ac84751-0338-43d1-be41-504b5aa8e9b5',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1342,4474,1,'2024-10-22 03:57:25','2024-10-22 03:57:25','decdf870-eecf-4a39-b688-24a387554901',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1343,4475,1,'2024-10-22 03:57:25','2024-10-22 03:57:25','1f000516-b27a-4cbd-90f4-d15674ed1e96','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1344,4476,1,'2024-10-22 03:57:25','2024-10-22 03:57:25','b2147351-7c9b-402d-96f6-933d183ea00e',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1345,4477,1,'2024-10-22 03:57:25','2024-10-22 03:57:25','cf499fd5-56a1-4a1d-88d6-752ae9f35985','ReferenceError: window is not defined','text',NULL),(1346,4478,1,'2024-10-22 03:57:25','2024-10-22 03:57:25','ee599d27-2ecb-4514-93e4-10ab08681b93',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1347,4479,1,'2024-10-22 03:57:25','2024-10-22 03:57:25','1a4df134-7272-49fc-9ebf-6790aac6c408','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1348,4480,1,'2024-10-22 03:57:25','2024-10-22 03:57:25','d2f4c08f-5008-4c13-9683-70dbaa124b82',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1349,4482,1,'2024-10-31 18:22:31','2024-10-31 18:22:31','4088f3a7-1e67-419f-911c-27cb43c4c753',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1350,4483,1,'2024-10-31 18:22:31','2024-10-31 18:22:31','682122e6-1c9a-48e9-9f9a-7bb37a3932eb','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1351,4484,1,'2024-10-31 18:22:31','2024-10-31 18:22:31','2bd752f0-6a3f-492b-ae34-632d0bd341b4',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1352,4485,1,'2024-10-31 18:22:31','2024-10-31 18:22:31','3bc4cca7-5cc3-4333-8472-518c55c8d3fa','ReferenceError: window is not defined','text',NULL),(1353,4486,1,'2024-10-31 18:22:31','2024-10-31 18:22:31','4f87e423-d21f-44bf-8f67-e08d160e185d',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1354,4487,1,'2024-10-31 18:22:31','2024-10-31 18:22:31','9fb29306-4e6f-4da5-bb84-142f050d26ff','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1355,4488,1,'2024-10-31 18:22:31','2024-10-31 18:22:31','d354d59a-4822-4670-8a59-f1228e515731',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1356,4490,1,'2024-12-12 16:11:21','2024-12-12 16:11:21','1c657739-5588-4f3b-a05e-caff8c21824c',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1357,4491,1,'2024-12-12 16:11:21','2024-12-12 16:11:21','3303dc6d-7c66-46d6-b813-9608ddbed09d','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1358,4492,1,'2024-12-12 16:11:21','2024-12-12 16:11:21','b8cd9903-00f0-4b98-82d9-5426fc37b636',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1359,4493,1,'2024-12-12 16:11:21','2024-12-12 16:11:21','23a687d0-0e88-44af-87c9-75e2ecf1033e','ReferenceError: window is not defined','text',NULL),(1360,4494,1,'2024-12-12 16:11:21','2024-12-12 16:11:21','36eb6ffb-df95-4e36-ac81-ab1cf1334c27',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1361,4495,1,'2024-12-12 16:11:21','2024-12-12 16:11:21','8160b6e0-accc-4bce-93c4-8b4bf57fe4c0','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1362,4496,1,'2024-12-12 16:11:21','2024-12-12 16:11:21','38a7b5fb-c2a9-45a1-8817-17d164351146',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1363,4498,1,'2024-12-12 16:11:23','2024-12-12 16:11:23','c2e0b410-5240-40d0-915e-5396f11d08d4',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1364,4499,1,'2024-12-12 16:11:23','2024-12-12 16:11:23','49786514-5547-4089-90ab-255f68c5d29d','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1365,4500,1,'2024-12-12 16:11:23','2024-12-12 16:11:23','7d841d0f-faa4-4bc3-aa27-0fb66625a79e',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1366,4501,1,'2024-12-12 16:11:23','2024-12-12 16:11:23','b6e26797-0709-4670-8ae5-7e4df6d25457','ReferenceError: window is not defined','text',NULL),(1367,4502,1,'2024-12-12 16:11:23','2024-12-12 16:11:23','6df0a728-efbc-403b-950d-a98139a53ba8',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1368,4503,1,'2024-12-12 16:11:23','2024-12-12 16:11:23','39fb64a3-251c-4b83-8676-9379bf0b1439','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1369,4504,1,'2024-12-12 16:11:23','2024-12-12 16:11:23','5fabacea-eb8e-441c-907c-1a047f670921',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1370,4506,1,'2024-12-12 16:11:25','2024-12-12 16:11:25','53549675-5ba8-44cc-a219-492548c970a7',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1371,4507,1,'2024-12-12 16:11:25','2024-12-12 16:11:25','df81b517-8532-44ca-b5c8-bf68ee5e0345','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1372,4508,1,'2024-12-12 16:11:25','2024-12-12 16:11:25','bb3261ac-b3ff-4ab6-8850-f2b17075d757',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1373,4509,1,'2024-12-12 16:11:25','2024-12-12 16:11:25','91ac1a66-3723-44a9-81c9-cbd178808f4c','ReferenceError: window is not defined','text',NULL),(1374,4510,1,'2024-12-12 16:11:25','2024-12-12 16:11:25','7866c9e4-5ea8-484d-b0d4-3c4a20446866',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1375,4511,1,'2024-12-12 16:11:25','2024-12-12 16:11:25','e2d8deee-4274-4a60-8d97-711ab34a0533','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1376,4512,1,'2024-12-12 16:11:25','2024-12-12 16:11:25','e6b83995-f867-48ce-baf1-f6d3336251db',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1377,4514,1,'2024-12-12 16:12:18','2024-12-12 16:12:18','22a095f0-aaf5-4232-a61b-87ff4f1bdffd',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1378,4515,1,'2024-12-12 16:12:18','2024-12-12 16:12:18','c1f0d754-500f-4056-a10a-f306f28de243','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1379,4516,1,'2024-12-12 16:12:18','2024-12-12 16:12:18','3ad9c2ed-61e4-4a33-a80e-7942fb1713f2',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1380,4517,1,'2024-12-12 16:12:18','2024-12-12 16:12:18','2541816f-bb60-42fc-ab91-fa076af33c5a','ReferenceError: window is not defined','text',NULL),(1381,4518,1,'2024-12-12 16:12:18','2024-12-12 16:12:18','7a5a5810-96ca-4350-9ec1-af9a03a8cf1c',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1382,4519,1,'2024-12-12 16:12:18','2024-12-12 16:12:18','b06d9a4e-aef8-45e8-a178-c6f9e886028d','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1383,4520,1,'2024-12-12 16:12:18','2024-12-12 16:12:18','e1fe14a2-6229-47ea-899c-75f12af5c3a6',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1384,4522,1,'2024-12-12 16:12:21','2024-12-12 16:12:21','ccbf54c6-b30f-44a7-a2e3-f63c2b30dc90',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1385,4523,1,'2024-12-12 16:12:21','2024-12-12 16:12:21','93fdc451-c2a3-4bd0-9d31-03cdd9e44d4a','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1386,4524,1,'2024-12-12 16:12:21','2024-12-12 16:12:21','4d93ab81-d02c-498c-b857-9e6ea382ac03',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1387,4525,1,'2024-12-12 16:12:21','2024-12-12 16:12:21','f39923fe-4a5c-4d95-905a-01e8b8a6b3cc','ReferenceError: window is not defined','text',NULL),(1388,4526,1,'2024-12-12 16:12:21','2024-12-12 16:12:21','41269f8d-2100-42d6-b525-b239a02ac6ec',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1389,4527,1,'2024-12-12 16:12:21','2024-12-12 16:12:21','eba43378-9733-41c6-9607-93ad8ea329fc','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1390,4528,1,'2024-12-12 16:12:21','2024-12-12 16:12:21','f2c9c928-de38-440a-98cc-7ab0f46ef4d0',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1391,4530,1,'2024-12-12 16:12:23','2024-12-12 16:12:23','7d270a5b-e0c8-46d5-b6a6-eeed42c8b98f',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1392,4531,1,'2024-12-12 16:12:23','2024-12-12 16:12:23','071fad39-2431-4cc6-a9d1-c9786c9f52cb','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1393,4532,1,'2024-12-12 16:12:23','2024-12-12 16:12:23','4e9c8ba8-4dfa-48b6-8078-bb54136d6c16',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1394,4533,1,'2024-12-12 16:12:23','2024-12-12 16:12:23','52b95dc4-00e3-4316-982a-06f0a1d96ff2','ReferenceError: window is not defined','text',NULL),(1395,4534,1,'2024-12-12 16:12:23','2024-12-12 16:12:23','2d8be729-ad08-4b0d-80a5-3df6a8f5d8c7',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1396,4535,1,'2024-12-12 16:12:23','2024-12-12 16:12:23','2f6b4075-f037-4077-b3f9-597f1fb9442f','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1397,4536,1,'2024-12-12 16:12:23','2024-12-12 16:12:23','a1bceb46-a05f-4121-a852-115d628b2b35',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1398,4538,1,'2024-12-12 16:12:26','2024-12-12 16:12:26','47c233af-329c-4b37-a6c8-9dd3a69a1a93',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1399,4539,1,'2024-12-12 16:12:26','2024-12-12 16:12:26','bc519400-6e2c-4e95-b826-69b5c3c16a40','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1400,4540,1,'2024-12-12 16:12:26','2024-12-12 16:12:26','09f2c70a-6755-4283-9a18-cc83f612bef7',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1401,4541,1,'2024-12-12 16:12:26','2024-12-12 16:12:26','538a1a35-7413-4eb0-acb2-f8452526b733','ReferenceError: window is not defined','text',NULL),(1402,4542,1,'2024-12-12 16:12:26','2024-12-12 16:12:26','f18a0159-a45c-4326-972c-993c7d507264',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1403,4543,1,'2024-12-12 16:12:26','2024-12-12 16:12:26','d82bb6e8-a515-4a50-b5ea-5303ba899779','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1404,4544,1,'2024-12-12 16:12:26','2024-12-12 16:12:26','4b18e9e9-d5f7-4030-a459-82074721d3dc',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1405,4546,1,'2024-12-12 16:12:28','2024-12-12 16:12:28','e9c16314-9758-4784-b234-bea7f6477546',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1406,4547,1,'2024-12-12 16:12:28','2024-12-12 16:12:28','af26a19a-29df-4631-a241-7e45c9de6c32','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1407,4548,1,'2024-12-12 16:12:28','2024-12-12 16:12:28','575c45b8-8f90-4ac5-bee3-ad680a38bc77',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1408,4549,1,'2024-12-12 16:12:28','2024-12-12 16:12:28','518175d7-1a7f-4918-9438-13caeadba8d4','ReferenceError: window is not defined','text',NULL),(1409,4550,1,'2024-12-12 16:12:28','2024-12-12 16:12:28','64ce54af-1ad9-4608-994a-3af917dcae9d',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1410,4551,1,'2024-12-12 16:12:28','2024-12-12 16:12:28','c851709d-0f73-4977-a3db-a0f072bcd8ac','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1411,4552,1,'2024-12-12 16:12:28','2024-12-12 16:12:28','881ed6f7-3781-4cf6-82a1-e9188c510a76',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1412,4554,1,'2024-12-17 16:39:36','2024-12-17 16:39:36','2d5947ba-ba54-4562-8532-5352fbbfca44',NULL,NULL,'<p>In my <a href=\"https://www.trevor-davis.com/blog/why-im-so-excited-about-remix\">previous post</a>, I talked about transitioning my site from being powered by <a href=\"https://craftcms.com/\">Craft</a> to being powered by <a href=\"https://remix.run/\">Remix</a> and a GraphQL endpoint coming from Craft. One of the best features of Craft is <a href=\"https://craftcms.com/features/all#live-preview\">Live Preview</a>, and it took a little configuration to get this working on my new Remix powered site.</p>\r\n<h2>Remix Configuration</h2>\r\n<p>These were specific changes that I needed to make on the Remix side, but really it would be the same for any GraphQL request. As Andrew Welch breaks down in <a href=\"https://nystudio107.com/blog/headless-preview-in-craft-cms\">his article</a>, the key is passing the token parameter back that Craft included in the URL.</p>\r\n<p>In the loader function of my blog post route, I call a helper function to setup the GraphQL client, and I pass the request to it:</p>'),(1413,4555,1,'2024-12-17 16:39:36','2024-12-17 16:39:36','30785990-6959-45be-8c0e-61fb284922cf','import { json } from \'remix\'\nimport { gql } from \'graphql-request\'\nimport { gqlClient } from \'graphql.server\'\n\nexport const loader = async ({ request }) => {\n    const { entries } = await gqlClient(request).request(gql`\n        {\n            YOUR GRAPHQL QUERY HERE\n        }\n    `)\n\n    return json({ entries })\n}','jsx',NULL),(1414,4556,1,'2024-12-17 16:39:36','2024-12-17 16:39:36','51e9bcef-4f0b-45b2-a64a-c1c017314c84',NULL,NULL,'<p>And then in my helper function, I take that request, grab the URL params that I want to include, and add those to my GraphQL request endpoint URL:</p>'),(1415,4557,1,'2024-12-17 16:39:36','2024-12-17 16:39:36','e57d4306-00cd-4812-b325-545170b06efa','import { GraphQLClient } from \'graphql-request\'\n\n// Extract allowed query params and construct query string\nconst getQueryParams = (request) => {\n    const url = new URL(request.url)\n    const allowedKeys = [\'x-craft-preview\', \'x-craft-live-preview\', \'token\']\n    const filteredParams = Object.entries(\n        Object.fromEntries(url.searchParams)\n    ).filter(([key]) => allowedKeys.includes(key))\n\n    if (!filteredParams.length) {\n        return \'\'\n    }\n\n    const queryString = filteredParams.map((val) => val.join(\'=\')).join(\'&\')\n\n    return `?${queryString}`\n}\n\nexport const gqlClient = (request = null) => {\n    const queryString = request ? getQueryParams(request) : \'\'\n\n    return new GraphQLClient(`https://your-endpoint-here/${queryString}`, {\n        headers: {\n            authorization: `Bearer YOUR_AUTH_TOKEN_HERE`,\n        },\n    })\n}','jsx',NULL),(1416,4558,1,'2024-12-17 16:39:36','2024-12-17 16:39:36','b193ada3-7525-4a38-a7e5-bb7af028d87d',NULL,NULL,'<p>It wasn’t totally necessary to include the <code>x-craft-preview</code> and <code>x-craft-live-preview</code> parameters, but I figured it couldn’t hurt.</p>\r\n<h2>Craft Configuration</h2>\r\n<p>Now with the Remix configuration in place, I just needed to make two small changes to Craft to get it working correctly. First, I had to update the preview target for my Blog section to point to my Remix site:</p>\r\n<figure><img src=\"{asset:2283:url||//assets.trevor-davis.com/uploads/images/content/blog-section-preview-target.png}\" data-image=\"2283\" alt=\"Setting the preview target in my Blog Section\"></figure>\r\n<p>Then, I had to update the <code>config/general.php</code> to allow iframe requests from my Remix domain:</p>'),(1417,4559,1,'2024-12-17 16:39:36','2024-12-17 16:39:36','b60a4196-0359-4308-9f8a-d07d237ed56c','<?php\n\nreturn [\n    \'*\' => [\n        \'headlessMode\' => true,\n        \'previewIframeResizerOptions\' => [\n            \'checkOrigin\' => [\n                \'https://www.trevor-davis.com\',\n            ],\n        ],\n    ],\n];','php',NULL),(1418,4560,1,'2024-12-17 16:39:36','2024-12-17 16:39:36','9ba41f5b-ee1d-48df-aa27-1004331d57f5',NULL,NULL,'<h2>Voilà, Live Preview</h2>\r\n<p>And just like that, I had live preview working.</p>\r\n<p><video src=\"{asset:2299:url||//assets.trevor-davis.com/uploads/images/content/live-preview.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\" width=\"100%\"></video></p>'),(1419,4610,1,'2025-01-18 16:07:21','2025-01-18 16:07:21','71dc2c71-e2f6-4b18-b6c9-e24b49d41e75',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1420,4611,1,'2025-01-18 16:07:21','2025-01-18 16:07:21','8b2524e2-9ebd-4028-b51f-db64f0d61f7c','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1421,4612,1,'2025-01-18 16:07:21','2025-01-18 16:07:21','c9a68071-1e74-4bd1-b98e-9f7296d69c57',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1422,4613,1,'2025-01-18 16:07:21','2025-01-18 16:07:21','7c12e5ff-f2bd-4a6f-8628-b0f61a8a9b47','ReferenceError: window is not defined','text',NULL),(1423,4614,1,'2025-01-18 16:07:21','2025-01-18 16:07:21','ab28581e-2fc7-4161-8cde-a127ea723c15',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1424,4615,1,'2025-01-18 16:07:21','2025-01-18 16:07:21','6622ead8-1aae-432f-8cfd-b1409582c59c','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1425,4616,1,'2025-01-18 16:07:21','2025-01-18 16:07:21','6de343b0-c25e-423d-b800-ce9130ea7c7e',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1426,4618,1,'2025-01-18 16:07:22','2025-01-18 16:07:22','34face2a-2955-464c-894f-2ee0ee1f13b3',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1427,4619,1,'2025-01-18 16:07:22','2025-01-18 16:07:22','e03f7628-ca12-4aac-875d-d948bacf6317','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1428,4620,1,'2025-01-18 16:07:22','2025-01-18 16:07:22','40f74936-a0ed-4c04-b129-2ec0f72855d0',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1429,4621,1,'2025-01-18 16:07:22','2025-01-18 16:07:22','daa5b86d-8aa9-4ecb-b163-0a577bd85614','ReferenceError: window is not defined','text',NULL),(1430,4622,1,'2025-01-18 16:07:22','2025-01-18 16:07:22','cbb5ae8b-4338-415d-ae84-e70527f40880',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1431,4623,1,'2025-01-18 16:07:22','2025-01-18 16:07:22','b8fbad11-9ada-436a-8766-4c9872ad5dff','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1432,4624,1,'2025-01-18 16:07:22','2025-01-18 16:07:22','cc29542e-02c0-4e0a-9caa-bb586da09576',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1433,4626,1,'2025-01-18 16:07:31','2025-01-18 16:07:31','388dc883-9528-4e86-a1cc-dc0665ef54b7',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1434,4627,1,'2025-01-18 16:07:31','2025-01-18 16:07:31','77db2e0d-abfd-4be5-bea8-351f693395b5','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1435,4628,1,'2025-01-18 16:07:31','2025-01-18 16:07:31','cf99cb5e-8c4a-45e6-8141-3a91855d5139',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1436,4629,1,'2025-01-18 16:07:31','2025-01-18 16:07:31','1a3d3071-33e0-4276-9115-b2512a69fb87','ReferenceError: window is not defined','text',NULL),(1437,4630,1,'2025-01-18 16:07:31','2025-01-18 16:07:31','54bcaa9b-cf46-411d-9534-45f0f0185a6a',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1438,4631,1,'2025-01-18 16:07:31','2025-01-18 16:07:31','b9884541-f24e-48e5-b0ba-f30daaf4a023','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1439,4632,1,'2025-01-18 16:07:31','2025-01-18 16:07:31','7d0b78f4-6783-4235-afb5-c5cfc17fb1c7',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1440,4634,1,'2025-01-18 16:07:32','2025-01-18 16:07:32','7605b8ce-ab2c-44a2-991b-188caa7532de',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1441,4635,1,'2025-01-18 16:07:32','2025-01-18 16:07:32','d5e532c2-b378-4566-a2da-0c8845d8998d','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1442,4636,1,'2025-01-18 16:07:32','2025-01-18 16:07:32','d3a48bb4-633a-4d19-b612-7c1a58cb8dc5',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1443,4637,1,'2025-01-18 16:07:32','2025-01-18 16:07:32','a8c0b8ed-9908-4506-b0f2-f8b2a512a789','ReferenceError: window is not defined','text',NULL),(1444,4638,1,'2025-01-18 16:07:32','2025-01-18 16:07:32','4b5835f2-fa8c-466b-ad1b-54163a4cdb95',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1445,4639,1,'2025-01-18 16:07:33','2025-01-18 16:07:33','517afe39-1fa5-4051-a253-52b4a7314288','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1446,4640,1,'2025-01-18 16:07:33','2025-01-18 16:07:33','96d47ca6-4494-4fc8-8f0f-f61b4423115e',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1447,4642,1,'2025-01-18 16:07:35','2025-01-18 16:07:35','615836d0-a711-43b6-8650-90203d02c514',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1448,4643,1,'2025-01-18 16:07:35','2025-01-18 16:07:35','1323c43c-78de-4031-8428-c98cfd413170','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1449,4644,1,'2025-01-18 16:07:35','2025-01-18 16:07:35','63418fb2-6ea1-4607-8b38-fd2c0559e603',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1450,4645,1,'2025-01-18 16:07:35','2025-01-18 16:07:35','093f2841-64e4-4e4a-b196-9b3eb09f042b','ReferenceError: window is not defined','text',NULL),(1451,4646,1,'2025-01-18 16:07:35','2025-01-18 16:07:35','ab01df8e-6620-46ea-b389-fed9b738932d',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1452,4647,1,'2025-01-18 16:07:35','2025-01-18 16:07:35','b29de2f9-dafd-41d6-914d-770332473550','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1453,4648,1,'2025-01-18 16:07:35','2025-01-18 16:07:35','14e51060-07e0-4af8-9546-da97c7b0d1bc',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1454,4650,1,'2025-01-18 16:07:36','2025-01-18 16:07:36','f905e323-aeee-4f0e-a479-11ad1f945e27',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1455,4651,1,'2025-01-18 16:07:36','2025-01-18 16:07:36','24161eed-2273-43c7-a53f-13e05fa0bfcd','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1456,4652,1,'2025-01-18 16:07:36','2025-01-18 16:07:36','112017cc-073d-4a7e-bb51-11029f69fc4b',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1457,4653,1,'2025-01-18 16:07:36','2025-01-18 16:07:36','adecdc32-2205-465a-bf44-02c11f18933e','ReferenceError: window is not defined','text',NULL),(1458,4654,1,'2025-01-18 16:07:36','2025-01-18 16:07:36','d7b434d5-361c-4e49-b6da-affde1f02ee1',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1459,4655,1,'2025-01-18 16:07:36','2025-01-18 16:07:36','32416e23-03e4-4bbe-88f6-a242bc12251f','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1460,4656,1,'2025-01-18 16:07:36','2025-01-18 16:07:36','cdf9c7ad-36eb-465e-9722-89a89bd76e26',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1461,4658,1,'2025-02-06 09:59:23','2025-02-06 09:59:23','c153b7dd-d9f2-4ecf-ab63-ed264950cb9b',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1462,4659,1,'2025-02-06 09:59:23','2025-02-06 09:59:23','b92edf3e-0afc-4dfe-9463-53fe0e43f595','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1463,4660,1,'2025-02-06 09:59:23','2025-02-06 09:59:23','f8e4a463-521e-4106-89f5-b505c9b2689a',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1464,4661,1,'2025-02-06 09:59:23','2025-02-06 09:59:23','f2ff0359-956e-4bf0-944d-e9a4f87386f6','ReferenceError: window is not defined','text',NULL),(1465,4662,1,'2025-02-06 09:59:23','2025-02-06 09:59:23','7a12d716-b7dd-4f88-9cb5-2387703af85f',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1466,4663,1,'2025-02-06 09:59:23','2025-02-06 09:59:23','e7bab048-287b-4882-bdfe-1b623d04ca53','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1467,4664,1,'2025-02-06 09:59:23','2025-02-06 09:59:23','0aff1025-e4d6-49bc-b4c5-67ed954a5481',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1468,4666,1,'2025-02-06 09:59:24','2025-02-06 09:59:24','84289ab7-48d3-4ce2-99d4-cb43cacdead0',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1469,4667,1,'2025-02-06 09:59:24','2025-02-06 09:59:24','4aae2076-8147-45f0-b7e8-ff6ab0638f25','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1470,4668,1,'2025-02-06 09:59:24','2025-02-06 09:59:24','14b88503-0b43-45ee-97d7-ecc75f1c30c0',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1471,4669,1,'2025-02-06 09:59:24','2025-02-06 09:59:24','793a8bbe-c798-41bc-bc06-deca4886d708','ReferenceError: window is not defined','text',NULL),(1472,4670,1,'2025-02-06 09:59:24','2025-02-06 09:59:24','ae2ff0ee-6ad0-4ae3-afc3-47ce57aeb88b',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1473,4671,1,'2025-02-06 09:59:24','2025-02-06 09:59:24','074c3748-608a-4b0b-9400-0249a9cc35cc','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1474,4672,1,'2025-02-06 09:59:24','2025-02-06 09:59:24','9e083758-9eca-4b6d-8e75-b45ec3e2b960',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1475,4674,1,'2025-02-06 09:59:25','2025-02-06 09:59:25','d18acaba-d25b-41d9-a3ed-2a7cb8fada1e',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1476,4675,1,'2025-02-06 09:59:25','2025-02-06 09:59:25','458cd021-311e-464a-a90c-bfc1763c9b30','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1477,4676,1,'2025-02-06 09:59:25','2025-02-06 09:59:25','4a96eea7-5990-4a82-a122-46a8412302ac',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1478,4677,1,'2025-02-06 09:59:25','2025-02-06 09:59:25','7feb3573-9b9b-4800-967b-641a70158964','ReferenceError: window is not defined','text',NULL),(1479,4678,1,'2025-02-06 09:59:25','2025-02-06 09:59:25','cc45bd67-4213-4670-9e36-ce7f6753ff4d',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1480,4679,1,'2025-02-06 09:59:25','2025-02-06 09:59:25','cc14ea28-fd02-486b-abaa-a832bb0dbd65','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1481,4680,1,'2025-02-06 09:59:25','2025-02-06 09:59:25','72ec3ed4-3276-4017-964a-52361af36c18',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1482,4682,1,'2025-02-06 09:59:26','2025-02-06 09:59:26','a386c3a4-91b3-4132-a43a-9042c2685a5a',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1483,4683,1,'2025-02-06 09:59:26','2025-02-06 09:59:26','72515c2a-c036-4d84-b97b-b3519de59112','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1484,4684,1,'2025-02-06 09:59:26','2025-02-06 09:59:26','085418b7-7ff6-4925-9f6f-ab628fe39dbd',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1485,4685,1,'2025-02-06 09:59:26','2025-02-06 09:59:26','474e1c1d-6d03-42f6-9248-fcbfe7e26fca','ReferenceError: window is not defined','text',NULL),(1486,4686,1,'2025-02-06 09:59:26','2025-02-06 09:59:26','f28847be-d8e8-4a0e-8767-c8eb4e5eb615',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1487,4687,1,'2025-02-06 09:59:26','2025-02-06 09:59:26','4275682f-35e6-4f36-8c94-f2328ad9c65b','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1488,4688,1,'2025-02-06 09:59:26','2025-02-06 09:59:26','9eb80336-1db3-4ea1-b063-43252597f36b',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1489,4690,1,'2025-02-06 09:59:27','2025-02-06 09:59:27','16cfb8d3-28d0-4c5f-987c-577648f97af0',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1490,4691,1,'2025-02-06 09:59:27','2025-02-06 09:59:27','21a4acd2-cf3b-4100-bce0-cf82ab738dd2','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1491,4692,1,'2025-02-06 09:59:27','2025-02-06 09:59:27','8baff531-efb8-4d3d-99c3-39941b5db8cb',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1492,4693,1,'2025-02-06 09:59:27','2025-02-06 09:59:27','b980f0d1-4986-4b4f-a110-519cc85579a8','ReferenceError: window is not defined','text',NULL),(1493,4694,1,'2025-02-06 09:59:27','2025-02-06 09:59:27','f9f4b0f4-831a-456b-afb3-5d702e6960eb',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1494,4695,1,'2025-02-06 09:59:27','2025-02-06 09:59:27','57f488c4-3be4-4668-bb3c-75dab20074f2','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1495,4696,1,'2025-02-06 09:59:27','2025-02-06 09:59:27','983749aa-a00b-4183-8c9c-5b422816ad55',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1496,4698,1,'2025-02-06 09:59:28','2025-02-06 09:59:28','13092433-956a-40c4-b634-8eb93b9d4591',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1497,4699,1,'2025-02-06 09:59:28','2025-02-06 09:59:28','74a802e6-18a5-458d-8468-b3365c962e5f','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1498,4700,1,'2025-02-06 09:59:28','2025-02-06 09:59:28','0ac253de-15de-4075-a4b1-9aab6b9b84ef',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1499,4701,1,'2025-02-06 09:59:28','2025-02-06 09:59:28','8d2e8c2a-c279-41f1-b4c9-1873249240ea','ReferenceError: window is not defined','text',NULL),(1500,4702,1,'2025-02-06 09:59:28','2025-02-06 09:59:28','0985eb85-71ce-49f2-aa5f-a551c0c5dcb9',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1501,4703,1,'2025-02-06 09:59:28','2025-02-06 09:59:28','f98acc58-4313-4382-94a4-07051e90f52a','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1502,4704,1,'2025-02-06 09:59:28','2025-02-06 09:59:28','48d56e96-f03f-43d9-a8f3-ee4382b5c8f2',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1503,4706,1,'2025-02-06 09:59:31','2025-02-06 09:59:31','e196bef6-0e00-4672-ac74-1ea71d39d14e',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1504,4707,1,'2025-02-06 09:59:31','2025-02-06 09:59:31','8c628086-baa0-4fc4-a06f-3ed04b4e6477','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1505,4708,1,'2025-02-06 09:59:31','2025-02-06 09:59:31','2ed4a488-f6cb-4c95-8a4e-44a5a38e0d2e',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1506,4709,1,'2025-02-06 09:59:31','2025-02-06 09:59:31','b86e39dc-324d-42b6-a007-34e15ece88ac','ReferenceError: window is not defined','text',NULL),(1507,4710,1,'2025-02-06 09:59:31','2025-02-06 09:59:31','a311afec-fced-4253-86b1-edb197974071',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1508,4711,1,'2025-02-06 09:59:31','2025-02-06 09:59:31','67d1bad4-cee3-4ec5-aa1d-cf8a360da01e','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1509,4712,1,'2025-02-06 09:59:31','2025-02-06 09:59:31','a1e4937b-2f7f-4a7f-8dcd-7bff980ed5f9',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1510,4714,1,'2025-02-22 15:01:04','2025-02-22 15:01:04','649b5e8a-45ec-40c9-b67c-f338e288a5cb',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1511,4715,1,'2025-02-22 15:01:04','2025-02-22 15:01:04','0089c8fe-0b1c-4ab5-b3e4-ba44d3535274','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1512,4716,1,'2025-02-22 15:01:04','2025-02-22 15:01:04','507f8d35-16ba-4535-a662-b43bb7688e78',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1513,4717,1,'2025-02-22 15:01:04','2025-02-22 15:01:04','2984f811-3b11-4a49-8fd0-d671ea4c6359','ReferenceError: window is not defined','text',NULL),(1514,4718,1,'2025-02-22 15:01:04','2025-02-22 15:01:04','c513e5ce-59dd-46ac-a2f0-0576d8a233e5',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1515,4719,1,'2025-02-22 15:01:04','2025-02-22 15:01:04','8b41a5b0-7a5b-4b34-9e4c-8aadffdb725e','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1516,4720,1,'2025-02-22 15:01:05','2025-02-22 15:01:05','cbc776e2-fadf-4e65-9f58-20dccc149c02',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1517,4722,1,'2025-02-22 15:01:06','2025-02-22 15:01:06','0ced0901-3b50-4ec9-89dd-568923190dc0',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1518,4723,1,'2025-02-22 15:01:06','2025-02-22 15:01:06','3bdf2968-bbae-4404-a960-e71646046995','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1519,4724,1,'2025-02-22 15:01:06','2025-02-22 15:01:06','c4b8183b-5c36-4700-8ee0-34f0f4cc17a8',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1520,4725,1,'2025-02-22 15:01:06','2025-02-22 15:01:06','cef648b7-ce8c-42b0-ad88-7d9efaba6892','ReferenceError: window is not defined','text',NULL),(1521,4726,1,'2025-02-22 15:01:06','2025-02-22 15:01:06','8ad59be5-6868-4bd4-aa51-83d867c7c040',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1522,4727,1,'2025-02-22 15:01:06','2025-02-22 15:01:06','24a7308f-7e12-4368-9e33-318065cb5b85','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1523,4728,1,'2025-02-22 15:01:06','2025-02-22 15:01:06','06971376-6dab-4d1c-8b44-67202797f419',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1524,4730,1,'2025-03-12 11:27:25','2025-03-12 11:27:25','7cf32c26-a425-4185-9e27-c6bd93d8e4e7',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1525,4731,1,'2025-03-12 11:27:25','2025-03-12 11:27:25','20c52a89-1e95-4d78-9490-1bb5e13bf26b','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1526,4732,1,'2025-03-12 11:27:25','2025-03-12 11:27:25','ad290df4-7a32-4e89-a4dd-3d134e297e33',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1527,4733,1,'2025-03-12 11:27:25','2025-03-12 11:27:25','0f5f6c87-2062-4807-b834-aa492244d77d','ReferenceError: window is not defined','text',NULL),(1528,4734,1,'2025-03-12 11:27:25','2025-03-12 11:27:25','43d5803a-332c-493c-9fa0-daa6bd0433ec',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1529,4735,1,'2025-03-12 11:27:25','2025-03-12 11:27:25','85abda13-f063-4fa4-bb9a-0c87afec8e6f','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1530,4736,1,'2025-03-12 11:27:25','2025-03-12 11:27:25','657f75c9-8bed-4e3d-87d6-30eaffa58dfd',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1531,4738,1,'2025-03-12 11:27:27','2025-03-12 11:27:27','a00a20a7-d975-4f02-9150-1ef4263aaad9',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1532,4739,1,'2025-03-12 11:27:27','2025-03-12 11:27:27','98655017-be1b-4125-9a9a-ed9deff2b6cf','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1533,4740,1,'2025-03-12 11:27:27','2025-03-12 11:27:27','55a4f49d-c496-445f-951f-e22b3fbee7cc',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1534,4741,1,'2025-03-12 11:27:27','2025-03-12 11:27:27','8a7314a0-ad2d-48e2-9bba-e83a9b3cf651','ReferenceError: window is not defined','text',NULL),(1535,4742,1,'2025-03-12 11:27:27','2025-03-12 11:27:27','bfc69a21-5835-4404-acdb-7f0067eff91c',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1536,4743,1,'2025-03-12 11:27:27','2025-03-12 11:27:27','48deeaf2-cd74-44ba-b4f8-936526758eba','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1537,4744,1,'2025-03-12 11:27:27','2025-03-12 11:27:27','40d0278b-7f31-44a4-806a-11d6e05299a0',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1538,4746,1,'2025-03-27 13:11:53','2025-03-27 13:11:53','e0be82dd-d1c1-4cb5-86c3-f758785b1ba4',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1539,4747,1,'2025-03-27 13:11:53','2025-03-27 13:11:53','f407e116-d71c-4689-87cd-284a1f18c6ed','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1540,4748,1,'2025-03-27 13:11:53','2025-03-27 13:11:53','1f7ac5cf-435e-4065-b412-a8101ff7b955',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1541,4749,1,'2025-03-27 13:11:53','2025-03-27 13:11:53','420ae36c-9c79-4069-b6af-b67a30855f80','ReferenceError: window is not defined','text',NULL),(1542,4750,1,'2025-03-27 13:11:53','2025-03-27 13:11:53','130107ae-1f6d-4777-968c-2fbf085837bc',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1543,4751,1,'2025-03-27 13:11:53','2025-03-27 13:11:53','2ec7954f-67c9-41ee-a999-f64e37bc3929','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1544,4752,1,'2025-03-27 13:11:53','2025-03-27 13:11:53','4aa62066-86cf-4311-a5c2-be06ba3110c4',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1545,4754,1,'2025-03-27 13:11:54','2025-03-27 13:11:54','f2633e1c-7841-4238-8ba4-0b120071b7b1',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1546,4755,1,'2025-03-27 13:11:54','2025-03-27 13:11:54','1e928f6f-3fdc-40db-ae2a-0e9ece786743','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1547,4756,1,'2025-03-27 13:11:54','2025-03-27 13:11:54','86443362-bf4a-4034-8782-becc355c3973',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1548,4757,1,'2025-03-27 13:11:54','2025-03-27 13:11:54','e8d907a1-4314-4723-99d1-9f96a255b5ab','ReferenceError: window is not defined','text',NULL),(1549,4758,1,'2025-03-27 13:11:54','2025-03-27 13:11:54','c7917340-fddb-4dbd-b2b7-0f5fee7ce3e7',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1550,4759,1,'2025-03-27 13:11:55','2025-03-27 13:11:55','abb836fa-9827-4653-96bc-70d03b707b1d','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1551,4760,1,'2025-03-27 13:11:55','2025-03-27 13:11:55','96f8ce3d-836f-490f-a208-3ac589d1425c',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1552,4762,1,'2025-03-27 13:12:00','2025-03-27 13:12:00','5313233f-cde7-425c-be98-5099ace8cf06',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1553,4763,1,'2025-03-27 13:12:00','2025-03-27 13:12:00','8e99be84-59d6-43ba-a86c-2f02aa7f2e22','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1554,4764,1,'2025-03-27 13:12:00','2025-03-27 13:12:00','b0ff2984-15d1-49c7-a1d8-338d4cccfb09',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1555,4765,1,'2025-03-27 13:12:00','2025-03-27 13:12:00','a44ba882-d8cf-4d7e-9d4c-ff2cb9210c18','ReferenceError: window is not defined','text',NULL),(1556,4766,1,'2025-03-27 13:12:00','2025-03-27 13:12:00','627b6b85-10f0-4fdb-87d6-8f202991a19a',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1557,4767,1,'2025-03-27 13:12:00','2025-03-27 13:12:00','b50d7b03-457e-47d9-ad8e-f13f182275ae','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1558,4768,1,'2025-03-27 13:12:00','2025-03-27 13:12:00','9b0da53f-e9f5-4096-b606-2abbb94d7d5d',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1559,4770,1,'2025-03-27 13:12:14','2025-03-27 13:12:14','6c722756-309a-4245-9c4b-c606845dc5ce',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1560,4771,1,'2025-03-27 13:12:14','2025-03-27 13:12:14','6612bc99-2e35-43cd-9604-90151ff6790d','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1561,4772,1,'2025-03-27 13:12:14','2025-03-27 13:12:14','cc795297-7e6d-49d9-a7aa-4a3d43d3c565',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1562,4773,1,'2025-03-27 13:12:14','2025-03-27 13:12:14','00926c5a-0192-4a65-8f73-a943b300f895','ReferenceError: window is not defined','text',NULL),(1563,4774,1,'2025-03-27 13:12:14','2025-03-27 13:12:14','9aa9741c-b31c-4fc3-b618-c3ef163d9770',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1564,4775,1,'2025-03-27 13:12:14','2025-03-27 13:12:14','f1eb3ef2-0416-4d92-8f3d-eef8046ce690','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1565,4776,1,'2025-03-27 13:12:14','2025-03-27 13:12:14','dd13ad4c-d80d-43ad-a054-b533b841c0a2',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>'),(1566,4778,1,'2025-03-27 13:12:16','2025-03-27 13:12:16','64da691a-65a0-4758-803a-1c0cdeecc294',NULL,NULL,'<p>I wanted to get some more experience working with GraphQL mutations, so I worked on a new feature for my site that enabled a user to “like” a blog article. I ran into a little gotcha that is kind of obvious now that I know the solution but wasn’t obvious at the time.</p>\r\n<p><video src=\"{asset:2490:url||//assets.trevor-davis.com/uploads/images/content/like-component.mp4}\" autoplay=\"\" loop=\"\" muted=\"\" controls=\"\"></video></p>\r\n<p>I didn’t think I needed to be fancy and store the “like” in the database and associate with the user, so I decided that tracking whether the user had liked the article in <code>localStorage</code> was enough and then keep track of the total article like count in the database. Seems easy enough right?</p>\r\n<h2>The Problem</h2>\r\n<p>This was my first approach in retrieving whether or not the user had liked the article from <code>localStorage</code>:</p>'),(1567,4779,1,'2025-03-27 13:12:16','2025-03-27 13:12:16','31b4161e-7efb-4685-8a24-ad1f5e4950fe','import { useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n})','jsx',NULL),(1568,4780,1,'2025-03-27 13:12:16','2025-03-27 13:12:16','f14c69ac-8153-4042-8337-82f11733ec15',NULL,NULL,'<p>And this is the error that I was getting:</p>'),(1569,4781,1,'2025-03-27 13:12:16','2025-03-27 13:12:16','20e02678-2953-46aa-984e-445a76fb8556','ReferenceError: window is not defined','text',NULL),(1570,4782,1,'2025-03-27 13:12:16','2025-03-27 13:12:16','fe97039e-9c28-436e-9a3f-1bcabe351784',NULL,NULL,'<h2>The Fix</h2>\r\n<p>At first I was &#x1f914;, but the fix is super simple and totally makes sense. Remix renders on the server, but I wanted to run this in the browser, so I simply needed to wrap it in a <code>useEffect</code>:</p>'),(1571,4783,1,'2025-03-27 13:12:16','2025-03-27 13:12:16','a0a114f9-8e53-4475-9e4a-ff1f10c4cddc','import { useEffect, useState } from \'react\'\n\nconst Like = ({ storageKey, likes }) => {\n    const [hasLiked, setHasLiked] = useState(false)\n\n    useEffect(() => {\n        setHasLiked(window.localStorage.getItem(storageKey) === \'true\')\n    }, [storageKey])\n})','jsx',NULL),(1572,4784,1,'2025-03-27 13:12:16','2025-03-27 13:12:16','e98fd677-01e3-4b32-bac6-972bcbd73174',NULL,NULL,'<p>This is actually captured in the <a href=\"https://remix.run/docs/en/v1/guides/constraints#rendering-with-browser-only-apis\">Remix docs</a>, but it was kind of buried.</p>');
commit;

--
-- Dumping data for table `craft_matrixcontent_experience`
--

set autocommit=0;
INSERT INTO `craft_matrixcontent_experience` VALUES (18,3624,1,'2024-04-15 18:36:12','2024-08-11 18:10:14','a345a5ae-2db7-4db9-aa64-7bed8e8a48de','2022-03-07 05:00:00','Dutchie','[{\"col1\":\"Senior Software Engineer II\",\"col2\":\"2022-03-07 05:00:00\",\"col3\":null}]','https://dutchie.com/','<ul><li>Responsible for building new features, accessibility improvements, and maintenance of ecommerce and admin React apps</li><li>Most of my time is spent in our Node monorepo but have also contributed to our Ruby on Rails app</li><li>Lead epics and mentor other engineers as needed</li></ul>'),(19,3631,1,'2024-04-15 18:36:12','2024-04-15 18:36:12','d4877eb6-fa13-46fc-bb57-e21d3be4bd88','2022-03-07 05:00:00','Dutchie','[{\"col1\":\"Senior Software Engineer II\",\"col2\":\"2022-03-07 05:00:00\",\"col3\":null}]','https://dutchie.com/','<ul><li>Responsible for new features, accessibility improvements, and maintenance of ecommerce Next.js and admin React apps</li><li>Most of my time is spent in our Node monorepo but have also contributed to our Ruby on Rails app</li><li>Lead epics and mentor other engineers as needed</li></ul>'),(55,3673,1,'2024-04-15 18:39:57','2024-08-11 18:10:14','5dfa01f4-5c2a-4bc6-836c-274018ec5c9d','2009-12-01 05:00:00','Viget','[{\"col1\":\"Front-End Development Technical Director\",\"col2\":\"2019-09-01 04:00:00\",\"col3\":\"2022-02-01 05:00:00\"},{\"col1\":\"Senior Front-End Developer\",\"col2\":\"2013-01-01 05:00:00\",\"col3\":\"2019-09-01 04:00:00\"},{\"col1\":\"Front-End Developer\",\"col2\":\"2009-12-01 05:00:00\",\"col3\":\"2013-01-01 05:00:00\"}]','https://www.viget.com/','<ul>\n<li>Built websites based on design files using semantic HTML, modular CSS, and efficient JavaScript with an emphasis on accessibility, reliability, and performance</li>\n<li>Concurrently served as tech lead on one main project and multiple support projects</li>\n<li>Led architecture and implementation of Craft CMS</li>\n<li>Led custom PHP development for Craft CMS integration</li>\n<li>Served on the DEI Advisory Committee</li>\n</ul>'),(56,3680,1,'2024-04-15 18:39:57','2024-04-15 18:39:57','abe274ca-557a-43ba-ad89-9503c9427d77','2022-03-07 05:00:00','Dutchie','[{\"col1\":\"Senior Software Engineer II\",\"col2\":\"2022-03-07 05:00:00\",\"col3\":null}]','https://dutchie.com/','<ul><li>Responsible for new features, accessibility improvements, and maintenance of ecommerce Next.js and admin React apps</li><li>Most of my time is spent in our Node monorepo but have also contributed to our Ruby on Rails app</li><li>Lead epics and mentor other engineers as needed</li></ul>'),(57,3681,1,'2024-04-15 18:39:57','2024-04-15 18:39:57','cb261cee-dc28-4fc2-a77f-9e46c4da4405','2009-12-01 05:00:00','Viget','[{\"col1\":\"Front-End Development Technical Director\",\"col2\":\"2019-09-01 04:00:00\",\"col3\":\"2022-02-01 05:00:00\"},{\"col1\":\"Senior Front-End Developer\",\"col2\":\"2013-01-01 05:00:00\",\"col3\":\"2019-09-01 04:00:00\"},{\"col1\":\"Front-End Developer\",\"col2\":\"2009-12-01 05:00:00\",\"col3\":\"2013-01-01 05:00:00\"}]','https://www.viget.com/','<ul>\n<li>Build websites using semantic HTML, modular CSS, and efficient JavaScript with an emphasis on accessibility, reliability, and performance</li>\n<li>Concurrently serve as tech lead on one main project and multiple support projects</li>\n<li>Lead architecture and implementation of Craft CMS</li>\n<li>Lead custom PHP development for Craft CMS integration</li>\n<li>Serve on the DEI Advisory Committee</li>\n</ul>'),(72,3702,1,'2024-04-15 18:41:19','2024-08-11 18:10:14','f2c06f9d-7c75-4d3f-a7ca-12ec2b763b22','2006-06-01 04:00:00','Matrix Group International','[{\"col1\":\"Front-End Developer\",\"col2\":\"2006-06-01 04:00:00\",\"col3\":\"2009-11-01 04:00:00\"}]','https://www.matrixgroup.net/','<ul><li>Built websites based on design files using standards compliant HTML, CSS, and JavaScript</li>\n<li>Implemented and extended custom ColdFusion CMS</li>\n<li>Implemented ExpressionEngine CMS</li>\n</ul>'),(73,3709,1,'2024-04-15 18:41:19','2024-04-15 18:41:19','b1fedd09-eb92-4575-84bd-290b0f6421f4','2022-03-07 05:00:00','Dutchie','[{\"col1\":\"Senior Software Engineer II\",\"col2\":\"2022-03-07 05:00:00\",\"col3\":null}]','https://dutchie.com/','<ul><li>Responsible for new features, accessibility improvements, and maintenance of ecommerce Next.js and admin React apps</li><li>Most of my time is spent in our Node monorepo but have also contributed to our Ruby on Rails app</li><li>Lead epics and mentor other engineers as needed</li></ul>'),(74,3710,1,'2024-04-15 18:41:19','2024-04-15 18:41:19','daea47e4-2136-4917-afa5-57798dacf44a','2009-12-01 05:00:00','Viget','[{\"col1\":\"Front-End Development Technical Director\",\"col2\":\"2019-09-01 04:00:00\",\"col3\":\"2022-02-01 05:00:00\"},{\"col1\":\"Senior Front-End Developer\",\"col2\":\"2013-01-01 05:00:00\",\"col3\":\"2019-09-01 04:00:00\"},{\"col1\":\"Front-End Developer\",\"col2\":\"2009-12-01 05:00:00\",\"col3\":\"2013-01-01 05:00:00\"}]','https://www.viget.com/','<ul>\n<li>Build websites using semantic HTML, modular CSS, and efficient JavaScript with an emphasis on accessibility, reliability, and performance</li>\n<li>Concurrently serve as tech lead on one main project and multiple support projects</li>\n<li>Lead architecture and implementation of Craft CMS</li>\n<li>Lead custom PHP development for Craft CMS integration</li>\n<li>Serve on the DEI Advisory Committee</li>\n</ul>'),(75,3711,1,'2024-04-15 18:41:19','2024-04-15 18:41:19','79d76975-5565-4097-9987-367edad302d2','2006-06-01 04:00:00','Matrix Group International','[{\"col1\":\"Front-End Developer\",\"col2\":\"2006-06-01 04:00:00\",\"col3\":\"2009-11-01 04:00:00\"}]','https://www.matrixgroup.net/','<p>TBD</p>'),(79,3727,1,'2024-04-15 18:43:26','2024-04-15 18:43:26','667b2c68-b6c4-4da1-bca0-21408a1a14ca','2022-03-07 05:00:00','Dutchie','[{\"col1\":\"Senior Software Engineer II\",\"col2\":\"2022-03-07 05:00:00\",\"col3\":null}]','https://dutchie.com/','<ul><li>Responsible for new features, accessibility improvements, and maintenance of ecommerce Next.js and admin React apps</li><li>Most of my time is spent in our Node monorepo but have also contributed to our Ruby on Rails app</li><li>Lead epics and mentor other engineers as needed</li></ul>'),(80,3728,1,'2024-04-15 18:43:26','2024-04-15 18:43:26','7a79988c-a51f-405a-ab4f-8f82ca5c5363','2009-12-01 05:00:00','Viget','[{\"col1\":\"Front-End Development Technical Director\",\"col2\":\"2019-09-01 04:00:00\",\"col3\":\"2022-02-01 05:00:00\"},{\"col1\":\"Senior Front-End Developer\",\"col2\":\"2013-01-01 05:00:00\",\"col3\":\"2019-09-01 04:00:00\"},{\"col1\":\"Front-End Developer\",\"col2\":\"2009-12-01 05:00:00\",\"col3\":\"2013-01-01 05:00:00\"}]','https://www.viget.com/','<ul>\n<li>Build websites using semantic HTML, modular CSS, and efficient JavaScript with an emphasis on accessibility, reliability, and performance</li>\n<li>Concurrently serve as tech lead on one main project and multiple support projects</li>\n<li>Lead architecture and implementation of Craft CMS</li>\n<li>Lead custom PHP development for Craft CMS integration</li>\n<li>Serve on the DEI Advisory Committee</li>\n</ul>'),(81,3729,1,'2024-04-15 18:43:26','2024-04-15 18:43:26','7b07e7b1-34aa-4d94-97a8-b921b3acd175','2006-06-01 04:00:00','Matrix Group International','[{\"col1\":\"Front-End Developer\",\"col2\":\"2006-06-01 04:00:00\",\"col3\":\"2009-11-01 04:00:00\"}]','https://www.matrixgroup.net/','<p>TBD</p>'),(85,3745,1,'2024-04-16 15:25:13','2024-04-16 15:25:13','fef07c5a-f2de-4a32-b7ae-06f39bf8522c','2022-03-07 05:00:00','Dutchie','[{\"col1\":\"Senior Software Engineer II\",\"col2\":\"2022-03-07 05:00:00\",\"col3\":null}]','https://dutchie.com/','<ul><li>Responsible for new features, accessibility improvements, and maintenance of ecommerce Next.js and admin React apps</li><li>Most of my time is spent in our Node monorepo but have also contributed to our Ruby on Rails app</li><li>Lead epics and mentor other engineers as needed</li></ul>'),(86,3746,1,'2024-04-16 15:25:13','2024-04-16 15:25:13','2c18b5c9-6281-4ea3-8023-aea8ff9f13ae','2009-12-01 05:00:00','Viget','[{\"col1\":\"Front-End Development Technical Director\",\"col2\":\"2019-09-01 04:00:00\",\"col3\":\"2022-02-01 05:00:00\"},{\"col1\":\"Senior Front-End Developer\",\"col2\":\"2013-01-01 05:00:00\",\"col3\":\"2019-09-01 04:00:00\"},{\"col1\":\"Front-End Developer\",\"col2\":\"2009-12-01 05:00:00\",\"col3\":\"2013-01-01 05:00:00\"}]','https://www.viget.com/','<ul>\n<li>Build websites using semantic HTML, modular CSS, and efficient JavaScript with an emphasis on accessibility, reliability, and performance</li>\n<li>Concurrently serve as tech lead on one main project and multiple support projects</li>\n<li>Lead architecture and implementation of Craft CMS</li>\n<li>Lead custom PHP development for Craft CMS integration</li>\n<li>Serve on the DEI Advisory Committee</li>\n</ul>'),(87,3747,1,'2024-04-16 15:25:14','2024-04-16 15:25:14','1f714453-14be-4707-a9db-1727695d6ee7','2006-06-01 04:00:00','Matrix Group International','[{\"col1\":\"Front-End Developer\",\"col2\":\"2006-06-01 04:00:00\",\"col3\":\"2009-11-01 04:00:00\"}]','https://www.matrixgroup.net/','<p>TBD</p>'),(91,3763,1,'2024-04-16 16:57:47','2024-04-16 16:57:47','672104e8-0db4-40a6-a4c8-b6d815a3a0e0','2022-03-07 05:00:00','Dutchie','[{\"col1\":\"Senior Software Engineer II\",\"col2\":\"2022-03-07 05:00:00\",\"col3\":null}]','https://dutchie.com/','<ul><li>Responsible for new features, accessibility improvements, and maintenance of ecommerce Next.js and admin React apps</li><li>Most of my time is spent in our Node monorepo but have also contributed to our Ruby on Rails app</li><li>Lead epics and mentor other engineers as needed</li></ul>'),(92,3764,1,'2024-04-16 16:57:47','2024-04-16 16:57:47','c65edbaf-777b-443e-9c46-06b04c035752','2009-12-01 05:00:00','Viget','[{\"col1\":\"Front-End Development Technical Director\",\"col2\":\"2019-09-01 04:00:00\",\"col3\":\"2022-02-01 05:00:00\"},{\"col1\":\"Senior Front-End Developer\",\"col2\":\"2013-01-01 05:00:00\",\"col3\":\"2019-09-01 04:00:00\"},{\"col1\":\"Front-End Developer\",\"col2\":\"2009-12-01 05:00:00\",\"col3\":\"2013-01-01 05:00:00\"}]','https://www.viget.com/','<ul>\n<li>Built websites using semantic HTML, modular CSS, and efficient JavaScript with an emphasis on accessibility, reliability, and performance</li>\n<li>Concurrently served as tech lead on one main project and multiple support projects</li>\n<li>Led architecture and implementation of Craft CMS</li>\n<li>Led custom PHP development for Craft CMS integration</li>\n<li>Served on the DEI Advisory Committee</li>\n</ul>'),(93,3765,1,'2024-04-16 16:57:47','2024-04-16 16:57:47','ea350094-5819-41f6-8ddc-c14bf0254f83','2006-06-01 04:00:00','Matrix Group International','[{\"col1\":\"Front-End Developer\",\"col2\":\"2006-06-01 04:00:00\",\"col3\":\"2009-11-01 04:00:00\"}]','https://www.matrixgroup.net/','<p>TBD</p>'),(97,3787,1,'2024-04-16 17:03:42','2024-04-16 17:03:42','5cbc5705-8fe8-4710-bf7a-d1316cc347a9','2022-03-07 05:00:00','Dutchie','[{\"col1\":\"Senior Software Engineer II\",\"col2\":\"2022-03-07 05:00:00\",\"col3\":null}]','https://dutchie.com/','<ul><li>Responsible for new features, accessibility improvements, and maintenance of ecommerce Next.js and admin React apps</li><li>Most of my time is spent in our Node monorepo but have also contributed to our Ruby on Rails app</li><li>Lead epics and mentor other engineers as needed</li></ul>'),(98,3788,1,'2024-04-16 17:03:42','2024-04-16 17:03:42','fe062452-a346-4e7c-935a-99d1259d3b32','2009-12-01 05:00:00','Viget','[{\"col1\":\"Front-End Development Technical Director\",\"col2\":\"2019-09-01 04:00:00\",\"col3\":\"2022-02-01 05:00:00\"},{\"col1\":\"Senior Front-End Developer\",\"col2\":\"2013-01-01 05:00:00\",\"col3\":\"2019-09-01 04:00:00\"},{\"col1\":\"Front-End Developer\",\"col2\":\"2009-12-01 05:00:00\",\"col3\":\"2013-01-01 05:00:00\"}]','https://www.viget.com/','<ul>\n<li>Built websites using semantic HTML, modular CSS, and efficient JavaScript with an emphasis on accessibility, reliability, and performance</li>\n<li>Concurrently served as tech lead on one main project and multiple support projects</li>\n<li>Led architecture and implementation of Craft CMS</li>\n<li>Led custom PHP development for Craft CMS integration</li>\n<li>Served on the DEI Advisory Committee</li>\n</ul>'),(99,3789,1,'2024-04-16 17:03:42','2024-04-16 17:03:42','2e9b3bb9-f663-4f9e-b36f-0d779839346f','2006-06-01 04:00:00','Matrix Group International','[{\"col1\":\"Front-End Developer\",\"col2\":\"2006-06-01 04:00:00\",\"col3\":\"2009-11-01 04:00:00\"}]','https://www.matrixgroup.net/','<p>TBD</p>'),(103,3805,1,'2024-04-16 17:10:04','2024-04-16 17:10:04','561868a8-a0ea-4dec-b613-a047efbcae4a','2022-03-07 05:00:00','Dutchie','[{\"col1\":\"Senior Software Engineer II\",\"col2\":\"2022-03-07 05:00:00\",\"col3\":null}]','https://dutchie.com/','<ul><li>Responsible for new features, accessibility improvements, and maintenance of ecommerce Next.js and admin React apps</li><li>Most of my time is spent in our Node monorepo but have also contributed to our Ruby on Rails app</li><li>Lead epics and mentor other engineers as needed</li></ul>'),(104,3806,1,'2024-04-16 17:10:04','2024-04-16 17:10:04','2c71e258-889e-40c4-9c10-d7da46b7f555','2009-12-01 05:00:00','Viget','[{\"col1\":\"Front-End Development Technical Director\",\"col2\":\"2019-09-01 04:00:00\",\"col3\":\"2022-02-01 05:00:00\"},{\"col1\":\"Senior Front-End Developer\",\"col2\":\"2013-01-01 05:00:00\",\"col3\":\"2019-09-01 04:00:00\"},{\"col1\":\"Front-End Developer\",\"col2\":\"2009-12-01 05:00:00\",\"col3\":\"2013-01-01 05:00:00\"}]','https://www.viget.com/','<ul>\n<li>Built websites from designs using semantic HTML, modular CSS, and efficient JavaScript with an emphasis on accessibility, reliability, and performance</li>\n<li>Concurrently served as tech lead on one main project and multiple support projects</li>\n<li>Led architecture and implementation of Craft CMS</li>\n<li>Led custom PHP development for Craft CMS integration</li>\n<li>Served on the DEI Advisory Committee</li>\n</ul>'),(105,3807,1,'2024-04-16 17:10:04','2024-04-16 17:10:04','1e11e2f7-c46b-4f5e-9d2d-079bfbd616c8','2006-06-01 04:00:00','Matrix Group International','[{\"col1\":\"Front-End Developer\",\"col2\":\"2006-06-01 04:00:00\",\"col3\":\"2009-11-01 04:00:00\"}]','https://www.matrixgroup.net/','<ul><li>Built websites from designs using standards compliant HTML, CSS, and JavaScript</li>\n<li>Implemented and extended custom ColdFusion CMS</li>\n<li>Implemented ExpressionEngine CMS</li>\n</ul>'),(109,3823,1,'2024-04-16 17:10:39','2024-04-16 17:10:39','09424c6a-689f-4244-8374-496db7622d51','2022-03-07 05:00:00','Dutchie','[{\"col1\":\"Senior Software Engineer II\",\"col2\":\"2022-03-07 05:00:00\",\"col3\":null}]','https://dutchie.com/','<ul><li>Responsible for new features, accessibility improvements, and maintenance of ecommerce Next.js and admin React apps</li><li>Most of my time is spent in our Node monorepo but have also contributed to our Ruby on Rails app</li><li>Lead epics and mentor other engineers as needed</li></ul>'),(110,3824,1,'2024-04-16 17:10:39','2024-04-16 17:10:39','1c689719-9538-40e4-a686-b9a0a41e0113','2009-12-01 05:00:00','Viget','[{\"col1\":\"Front-End Development Technical Director\",\"col2\":\"2019-09-01 04:00:00\",\"col3\":\"2022-02-01 05:00:00\"},{\"col1\":\"Senior Front-End Developer\",\"col2\":\"2013-01-01 05:00:00\",\"col3\":\"2019-09-01 04:00:00\"},{\"col1\":\"Front-End Developer\",\"col2\":\"2009-12-01 05:00:00\",\"col3\":\"2013-01-01 05:00:00\"}]','https://www.viget.com/','<ul>\n<li>Built websites based on design files using semantic HTML, modular CSS, and efficient JavaScript with an emphasis on accessibility, reliability, and performance</li>\n<li>Concurrently served as tech lead on one main project and multiple support projects</li>\n<li>Led architecture and implementation of Craft CMS</li>\n<li>Led custom PHP development for Craft CMS integration</li>\n<li>Served on the DEI Advisory Committee</li>\n</ul>'),(111,3825,1,'2024-04-16 17:10:39','2024-04-16 17:10:39','959730ec-4cc0-4bf0-9e14-f4629c7d69b2','2006-06-01 04:00:00','Matrix Group International','[{\"col1\":\"Front-End Developer\",\"col2\":\"2006-06-01 04:00:00\",\"col3\":\"2009-11-01 04:00:00\"}]','https://www.matrixgroup.net/','<ul><li>Built websites based on design files using standards compliant HTML, CSS, and JavaScript</li>\n<li>Implemented and extended custom ColdFusion CMS</li>\n<li>Implemented ExpressionEngine CMS</li>\n</ul>'),(115,3843,1,'2024-04-16 17:16:09','2024-04-16 17:16:09','f8456556-0751-4b15-b82a-9ccccaa32bc3','2022-03-07 05:00:00','Dutchie','[{\"col1\":\"Senior Software Engineer II\",\"col2\":\"2022-03-07 05:00:00\",\"col3\":null}]','https://dutchie.com/','<ul><li>Responsible for new features, accessibility improvements, and maintenance of ecommerce Next.js and admin React apps</li><li>Most of my time is spent in our Node monorepo but have also contributed to our Ruby on Rails app</li><li>Lead epics and mentor other engineers as needed</li></ul>'),(116,3844,1,'2024-04-16 17:16:09','2024-04-16 17:16:09','79939981-b2f6-44a7-809b-7c4a3efa9eaf','2009-12-01 05:00:00','Viget','[{\"col1\":\"Front-End Development Technical Director\",\"col2\":\"2019-09-01 04:00:00\",\"col3\":\"2022-02-01 05:00:00\"},{\"col1\":\"Senior Front-End Developer\",\"col2\":\"2013-01-01 05:00:00\",\"col3\":\"2019-09-01 04:00:00\"},{\"col1\":\"Front-End Developer\",\"col2\":\"2009-12-01 05:00:00\",\"col3\":\"2013-01-01 05:00:00\"}]','https://www.viget.com/','<ul>\n<li>Built websites based on design files using semantic HTML, modular CSS, and efficient JavaScript with an emphasis on accessibility, reliability, and performance</li>\n<li>Concurrently served as tech lead on one main project and multiple support projects</li>\n<li>Led architecture and implementation of Craft CMS</li>\n<li>Led custom PHP development for Craft CMS integration</li>\n<li>Served on the DEI Advisory Committee</li>\n</ul>'),(117,3845,1,'2024-04-16 17:16:09','2024-04-16 17:16:09','7d291488-7ac8-4238-993a-7d8af196d666','2006-06-01 04:00:00','Matrix Group International','[{\"col1\":\"Front-End Developer\",\"col2\":\"2006-06-01 04:00:00\",\"col3\":\"2009-11-01 04:00:00\"}]','https://www.matrixgroup.net/','<ul><li>Built websites based on design files using standards compliant HTML, CSS, and JavaScript</li>\n<li>Implemented and extended custom ColdFusion CMS</li>\n<li>Implemented ExpressionEngine CMS</li>\n</ul>'),(121,3861,1,'2024-04-16 17:16:27','2024-04-16 17:16:27','3b550137-f5d0-4be3-9393-83c18858ac9d','2022-03-07 05:00:00','Dutchie','[{\"col1\":\"Senior Software Engineer II\",\"col2\":\"2022-03-07 05:00:00\",\"col3\":null}]','https://dutchie.com/','<ul><li>Responsible for new features, accessibility improvements, and maintenance of ecommerce Next.js and admin React apps</li><li>Most of my time is spent in our Node monorepo but have also contributed to our Ruby on Rails app</li><li>Lead epics and mentor other engineers as needed</li></ul>'),(122,3862,1,'2024-04-16 17:16:27','2024-04-16 17:16:27','1ee4a90a-c54b-46ac-bd6c-f7eaa64d5f88','2009-12-01 05:00:00','Viget','[{\"col1\":\"Front-End Development Technical Director\",\"col2\":\"2019-09-01 04:00:00\",\"col3\":\"2022-02-01 05:00:00\"},{\"col1\":\"Senior Front-End Developer\",\"col2\":\"2013-01-01 05:00:00\",\"col3\":\"2019-09-01 04:00:00\"},{\"col1\":\"Front-End Developer\",\"col2\":\"2009-12-01 05:00:00\",\"col3\":\"2013-01-01 05:00:00\"}]','https://www.viget.com/','<ul>\n<li>Built websites based on design files using semantic HTML, modular CSS, and efficient JavaScript with an emphasis on accessibility, reliability, and performance</li>\n<li>Concurrently served as tech lead on one main project and multiple support projects</li>\n<li>Led architecture and implementation of Craft CMS</li>\n<li>Led custom PHP development for Craft CMS integration</li>\n<li>Served on the DEI Advisory Committee</li>\n</ul>'),(123,3863,1,'2024-04-16 17:16:27','2024-04-16 17:16:27','7f823180-4ca7-4fb7-bee4-68725735b701','2006-06-01 04:00:00','Matrix Group International','[{\"col1\":\"Front-End Developer\",\"col2\":\"2006-06-01 04:00:00\",\"col3\":\"2009-11-01 04:00:00\"}]','https://www.matrixgroup.net/','<ul><li>Built websites based on design files using standards compliant HTML, CSS, and JavaScript</li>\n<li>Implemented and extended custom ColdFusion CMS</li>\n<li>Implemented ExpressionEngine CMS</li>\n</ul>'),(127,3880,1,'2024-04-16 17:29:55','2024-04-16 17:29:55','4aee3783-9f95-4425-8cbd-bd13f464072f','2022-03-07 05:00:00','Dutchie','[{\"col1\":\"Senior Software Engineer II\",\"col2\":\"2022-03-07 05:00:00\",\"col3\":null}]','https://dutchie.com/','<ul><li>Responsible for new features, accessibility improvements, and maintenance of ecommerce Next.js and admin React apps</li><li>Most of my time is spent in our Node monorepo but have also contributed to our Ruby on Rails app</li><li>Lead epics and mentor other engineers as needed</li></ul>'),(128,3881,1,'2024-04-16 17:29:55','2024-04-16 17:29:55','4c7820db-5d10-49ca-b09e-9f17f9bb0619','2009-12-01 05:00:00','Viget','[{\"col1\":\"Front-End Development Technical Director\",\"col2\":\"2019-09-01 04:00:00\",\"col3\":\"2022-02-01 05:00:00\"},{\"col1\":\"Senior Front-End Developer\",\"col2\":\"2013-01-01 05:00:00\",\"col3\":\"2019-09-01 04:00:00\"},{\"col1\":\"Front-End Developer\",\"col2\":\"2009-12-01 05:00:00\",\"col3\":\"2013-01-01 05:00:00\"}]','https://www.viget.com/','<ul>\n<li>Built websites based on design files using semantic HTML, modular CSS, and efficient JavaScript with an emphasis on accessibility, reliability, and performance</li>\n<li>Concurrently served as tech lead on one main project and multiple support projects</li>\n<li>Led architecture and implementation of Craft CMS</li>\n<li>Led custom PHP development for Craft CMS integration</li>\n<li>Served on the DEI Advisory Committee</li>\n</ul>'),(129,3882,1,'2024-04-16 17:29:55','2024-04-16 17:29:55','f3a8cc49-4571-43ca-9564-42a0d7631dbe','2006-06-01 04:00:00','Matrix Group International','[{\"col1\":\"Front-End Developer\",\"col2\":\"2006-06-01 04:00:00\",\"col3\":\"2009-11-01 04:00:00\"}]','https://www.matrixgroup.net/','<ul><li>Built websites based on design files using standards compliant HTML, CSS, and JavaScript</li>\n<li>Implemented and extended custom ColdFusion CMS</li>\n<li>Implemented ExpressionEngine CMS</li>\n</ul>'),(133,3898,1,'2024-04-16 17:50:17','2024-04-16 17:50:17','1beed720-7b34-41e2-8fda-d86f0807e311','2022-03-07 05:00:00','Dutchie','[{\"col1\":\"Senior Software Engineer II\",\"col2\":\"2022-03-07 05:00:00\",\"col3\":null}]','https://dutchie.com/','<ul><li>Responsible for new features, accessibility improvements, and maintenance of ecommerce Next.js and admin React apps</li><li>Most of my time is spent in our Node monorepo but have also contributed to our Ruby on Rails app</li><li>Lead epics and mentor other engineers as needed</li></ul>'),(134,3899,1,'2024-04-16 17:50:17','2024-04-16 17:50:17','fde9b364-1f1f-4290-bc1c-a61a8c3b331a','2009-12-01 05:00:00','Viget','[{\"col1\":\"Front-End Development Technical Director\",\"col2\":\"2019-09-01 04:00:00\",\"col3\":\"2022-02-01 05:00:00\"},{\"col1\":\"Senior Front-End Developer\",\"col2\":\"2013-01-01 05:00:00\",\"col3\":\"2019-09-01 04:00:00\"},{\"col1\":\"Front-End Developer\",\"col2\":\"2009-12-01 05:00:00\",\"col3\":\"2013-01-01 05:00:00\"}]','https://www.viget.com/','<ul>\n<li>Built websites based on design files using semantic HTML, modular CSS, and efficient JavaScript with an emphasis on accessibility, reliability, and performance</li>\n<li>Concurrently served as tech lead on one main project and multiple support projects</li>\n<li>Led architecture and implementation of Craft CMS</li>\n<li>Led custom PHP development for Craft CMS integration</li>\n<li>Served on the DEI Advisory Committee</li>\n</ul>'),(135,3900,1,'2024-04-16 17:50:17','2024-04-16 17:50:17','d965c6a1-525f-45b6-9444-b5631f719a4f','2006-06-01 04:00:00','Matrix Group International','[{\"col1\":\"Front-End Developer\",\"col2\":\"2006-06-01 04:00:00\",\"col3\":\"2009-11-01 04:00:00\"}]','https://www.matrixgroup.net/','<ul><li>Built websites based on design files using standards compliant HTML, CSS, and JavaScript</li>\n<li>Implemented and extended custom ColdFusion CMS</li>\n<li>Implemented ExpressionEngine CMS</li>\n</ul>'),(139,3916,1,'2024-04-16 17:50:34','2024-04-16 17:50:34','270ac2ec-92ae-4df5-a6d8-c48c9f9cb3fe','2022-03-07 05:00:00','Dutchie','[{\"col1\":\"Senior Software Engineer II\",\"col2\":\"2022-03-07 05:00:00\",\"col3\":null}]','https://dutchie.com/','<ul><li>Responsible for new features, accessibility improvements, and maintenance of ecommerce Next.js and admin React apps</li><li>Most of my time is spent in our Node monorepo but have also contributed to our Ruby on Rails app</li><li>Lead epics and mentor other engineers as needed</li></ul>'),(140,3917,1,'2024-04-16 17:50:34','2024-04-16 17:50:34','06b03e1f-7189-465b-8f15-542bfabc2986','2009-12-01 05:00:00','Viget','[{\"col1\":\"Front-End Development Technical Director\",\"col2\":\"2019-09-01 04:00:00\",\"col3\":\"2022-02-01 05:00:00\"},{\"col1\":\"Senior Front-End Developer\",\"col2\":\"2013-01-01 05:00:00\",\"col3\":\"2019-09-01 04:00:00\"},{\"col1\":\"Front-End Developer\",\"col2\":\"2009-12-01 05:00:00\",\"col3\":\"2013-01-01 05:00:00\"}]','https://www.viget.com/','<ul>\n<li>Built websites based on design files using semantic HTML, modular CSS, and efficient JavaScript with an emphasis on accessibility, reliability, and performance</li>\n<li>Concurrently served as tech lead on one main project and multiple support projects</li>\n<li>Led architecture and implementation of Craft CMS</li>\n<li>Led custom PHP development for Craft CMS integration</li>\n<li>Served on the DEI Advisory Committee</li>\n</ul>'),(141,3918,1,'2024-04-16 17:50:34','2024-04-16 17:50:34','1778670a-d37b-4ebd-ade8-36651a429a5b','2006-06-01 04:00:00','Matrix Group International','[{\"col1\":\"Front-End Developer\",\"col2\":\"2006-06-01 04:00:00\",\"col3\":\"2009-11-01 04:00:00\"}]','https://www.matrixgroup.net/','<ul><li>Built websites based on design files using standards compliant HTML, CSS, and JavaScript</li>\n<li>Implemented and extended custom ColdFusion CMS</li>\n<li>Implemented ExpressionEngine CMS</li>\n</ul>'),(145,3934,1,'2024-04-16 17:51:08','2024-04-16 17:51:08','23d39bcf-5476-4371-b8e7-841042a6b42e','2022-03-07 05:00:00','Dutchie','[{\"col1\":\"Senior Software Engineer II\",\"col2\":\"2022-03-07 05:00:00\",\"col3\":null}]','https://dutchie.com/','<ul><li>Responsible for new features, accessibility improvements, and maintenance of ecommerce Next.js and admin React apps</li><li>Most of my time is spent in our Node monorepo but have also contributed to our Ruby on Rails app</li><li>Lead epics and mentor other engineers as needed</li></ul>'),(146,3935,1,'2024-04-16 17:51:08','2024-04-16 17:51:08','92be20ce-6b62-4764-a897-6783fbc76d45','2009-12-01 05:00:00','Viget','[{\"col1\":\"Front-End Development Technical Director\",\"col2\":\"2019-09-01 04:00:00\",\"col3\":\"2022-02-01 05:00:00\"},{\"col1\":\"Senior Front-End Developer\",\"col2\":\"2013-01-01 05:00:00\",\"col3\":\"2019-09-01 04:00:00\"},{\"col1\":\"Front-End Developer\",\"col2\":\"2009-12-01 05:00:00\",\"col3\":\"2013-01-01 05:00:00\"}]','https://www.viget.com/','<ul>\n<li>Built websites based on design files using semantic HTML, modular CSS, and efficient JavaScript with an emphasis on accessibility, reliability, and performance</li>\n<li>Concurrently served as tech lead on one main project and multiple support projects</li>\n<li>Led architecture and implementation of Craft CMS</li>\n<li>Led custom PHP development for Craft CMS integration</li>\n<li>Served on the DEI Advisory Committee</li>\n</ul>'),(147,3936,1,'2024-04-16 17:51:08','2024-04-16 17:51:08','d8f143c4-9c73-41ef-b6ce-61ec4de94c9e','2006-06-01 04:00:00','Matrix Group International','[{\"col1\":\"Front-End Developer\",\"col2\":\"2006-06-01 04:00:00\",\"col3\":\"2009-11-01 04:00:00\"}]','https://www.matrixgroup.net/','<ul><li>Built websites based on design files using standards compliant HTML, CSS, and JavaScript</li>\n<li>Implemented and extended custom ColdFusion CMS</li>\n<li>Implemented ExpressionEngine CMS</li>\n</ul>'),(151,3952,1,'2024-04-16 17:51:35','2024-04-16 17:51:35','b440d8db-7688-4297-a829-a5c26364b103','2022-03-07 05:00:00','Dutchie','[{\"col1\":\"Senior Software Engineer II\",\"col2\":\"2022-03-07 05:00:00\",\"col3\":null}]','https://dutchie.com/','<ul><li>Responsible for new features, accessibility improvements, and maintenance of ecommerce Next.js and admin React apps</li><li>Most of my time is spent in our Node monorepo but have also contributed to our Ruby on Rails app</li><li>Lead epics and mentor other engineers as needed</li></ul>'),(152,3953,1,'2024-04-16 17:51:35','2024-04-16 17:51:35','6774f844-470b-417a-a82d-24b6568c24df','2009-12-01 05:00:00','Viget','[{\"col1\":\"Front-End Development Technical Director\",\"col2\":\"2019-09-01 04:00:00\",\"col3\":\"2022-02-01 05:00:00\"},{\"col1\":\"Senior Front-End Developer\",\"col2\":\"2013-01-01 05:00:00\",\"col3\":\"2019-09-01 04:00:00\"},{\"col1\":\"Front-End Developer\",\"col2\":\"2009-12-01 05:00:00\",\"col3\":\"2013-01-01 05:00:00\"}]','https://www.viget.com/','<ul>\n<li>Built websites based on design files using semantic HTML, modular CSS, and efficient JavaScript with an emphasis on accessibility, reliability, and performance</li>\n<li>Concurrently served as tech lead on one main project and multiple support projects</li>\n<li>Led architecture and implementation of Craft CMS</li>\n<li>Led custom PHP development for Craft CMS integration</li>\n<li>Served on the DEI Advisory Committee</li>\n</ul>'),(153,3954,1,'2024-04-16 17:51:35','2024-04-16 17:51:35','bd8e7c36-8266-487d-b10a-b25906acb2a2','2006-06-01 04:00:00','Matrix Group International','[{\"col1\":\"Front-End Developer\",\"col2\":\"2006-06-01 04:00:00\",\"col3\":\"2009-11-01 04:00:00\"}]','https://www.matrixgroup.net/','<ul><li>Built websites based on design files using standards compliant HTML, CSS, and JavaScript</li>\n<li>Implemented and extended custom ColdFusion CMS</li>\n<li>Implemented ExpressionEngine CMS</li>\n</ul>'),(157,3970,1,'2024-04-16 17:51:59','2024-04-16 17:51:59','09e22fc0-5e0e-4bc0-bfa2-56471aaab61b','2022-03-07 05:00:00','Dutchie','[{\"col1\":\"Senior Software Engineer II\",\"col2\":\"2022-03-07 05:00:00\",\"col3\":null}]','https://dutchie.com/','<ul><li>Responsible for new features, accessibility improvements, and maintenance of ecommerce Next.js and admin React apps</li><li>Most of my time is spent in our Node monorepo but have also contributed to our Ruby on Rails app</li><li>Lead epics and mentor other engineers as needed</li></ul>'),(158,3971,1,'2024-04-16 17:51:59','2024-04-16 17:51:59','4ba9e9a6-998a-4dc4-a4a8-0b236224ae7c','2009-12-01 05:00:00','Viget','[{\"col1\":\"Front-End Development Technical Director\",\"col2\":\"2019-09-01 04:00:00\",\"col3\":\"2022-02-01 05:00:00\"},{\"col1\":\"Senior Front-End Developer\",\"col2\":\"2013-01-01 05:00:00\",\"col3\":\"2019-09-01 04:00:00\"},{\"col1\":\"Front-End Developer\",\"col2\":\"2009-12-01 05:00:00\",\"col3\":\"2013-01-01 05:00:00\"}]','https://www.viget.com/','<ul>\n<li>Built websites based on design files using semantic HTML, modular CSS, and efficient JavaScript with an emphasis on accessibility, reliability, and performance</li>\n<li>Concurrently served as tech lead on one main project and multiple support projects</li>\n<li>Led architecture and implementation of Craft CMS</li>\n<li>Led custom PHP development for Craft CMS integration</li>\n<li>Served on the DEI Advisory Committee</li>\n</ul>'),(159,3972,1,'2024-04-16 17:51:59','2024-04-16 17:51:59','dc5a1fde-0303-4531-bcd9-542e7dd0cb3d','2006-06-01 04:00:00','Matrix Group International','[{\"col1\":\"Front-End Developer\",\"col2\":\"2006-06-01 04:00:00\",\"col3\":\"2009-11-01 04:00:00\"}]','https://www.matrixgroup.net/','<ul><li>Built websites based on design files using standards compliant HTML, CSS, and JavaScript</li>\n<li>Implemented and extended custom ColdFusion CMS</li>\n<li>Implemented ExpressionEngine CMS</li>\n</ul>'),(163,3988,1,'2024-04-16 17:52:15','2024-04-16 17:52:15','cad7cb2f-173a-4d0a-b4b8-c5a96c60e71a','2022-03-07 05:00:00','Dutchie','[{\"col1\":\"Senior Software Engineer II\",\"col2\":\"2022-03-07 05:00:00\",\"col3\":null}]','https://dutchie.com/','<ul><li>Responsible for new features, accessibility improvements, and maintenance of ecommerce Next.js and admin React apps</li><li>Most of my time is spent in our Node monorepo but have also contributed to our Ruby on Rails app</li><li>Lead epics and mentor other engineers as needed</li></ul>'),(164,3989,1,'2024-04-16 17:52:15','2024-04-16 17:52:15','bcc5b3ec-11c1-4c08-ac72-595cdb70527a','2009-12-01 05:00:00','Viget','[{\"col1\":\"Front-End Development Technical Director\",\"col2\":\"2019-09-01 04:00:00\",\"col3\":\"2022-02-01 05:00:00\"},{\"col1\":\"Senior Front-End Developer\",\"col2\":\"2013-01-01 05:00:00\",\"col3\":\"2019-09-01 04:00:00\"},{\"col1\":\"Front-End Developer\",\"col2\":\"2009-12-01 05:00:00\",\"col3\":\"2013-01-01 05:00:00\"}]','https://www.viget.com/','<ul>\n<li>Built websites based on design files using semantic HTML, modular CSS, and efficient JavaScript with an emphasis on accessibility, reliability, and performance</li>\n<li>Concurrently served as tech lead on one main project and multiple support projects</li>\n<li>Led architecture and implementation of Craft CMS</li>\n<li>Led custom PHP development for Craft CMS integration</li>\n<li>Served on the DEI Advisory Committee</li>\n</ul>'),(165,3990,1,'2024-04-16 17:52:15','2024-04-16 17:52:15','bc9fffe6-679e-4e72-8124-9c1930a97512','2006-06-01 04:00:00','Matrix Group International','[{\"col1\":\"Front-End Developer\",\"col2\":\"2006-06-01 04:00:00\",\"col3\":\"2009-11-01 04:00:00\"}]','https://www.matrixgroup.net/','<ul><li>Built websites based on design files using standards compliant HTML, CSS, and JavaScript</li>\n<li>Implemented and extended custom ColdFusion CMS</li>\n<li>Implemented ExpressionEngine CMS</li>\n</ul>'),(169,4358,1,'2024-08-11 18:10:14','2024-08-11 18:10:14','606e180e-1661-4483-b682-44441df47907','2022-03-07 05:00:00','Dutchie','[{\"col1\":\"Senior Software Engineer II\",\"col2\":\"2022-03-07 05:00:00\",\"col3\":null}]','https://dutchie.com/','<ul><li>Responsible for building new features, accessibility improvements, and maintenance of ecommerce and admin React apps</li><li>Most of my time is spent in our Node monorepo but have also contributed to our Ruby on Rails app</li><li>Lead epics and mentor other engineers as needed</li></ul>'),(170,4359,1,'2024-08-11 18:10:14','2024-08-11 18:10:14','4af2eaf8-282a-4eee-9b8d-ceda4de02220','2009-12-01 05:00:00','Viget','[{\"col1\":\"Front-End Development Technical Director\",\"col2\":\"2019-09-01 04:00:00\",\"col3\":\"2022-02-01 05:00:00\"},{\"col1\":\"Senior Front-End Developer\",\"col2\":\"2013-01-01 05:00:00\",\"col3\":\"2019-09-01 04:00:00\"},{\"col1\":\"Front-End Developer\",\"col2\":\"2009-12-01 05:00:00\",\"col3\":\"2013-01-01 05:00:00\"}]','https://www.viget.com/','<ul>\n<li>Built websites based on design files using semantic HTML, modular CSS, and efficient JavaScript with an emphasis on accessibility, reliability, and performance</li>\n<li>Concurrently served as tech lead on one main project and multiple support projects</li>\n<li>Led architecture and implementation of Craft CMS</li>\n<li>Led custom PHP development for Craft CMS integration</li>\n<li>Served on the DEI Advisory Committee</li>\n</ul>'),(171,4360,1,'2024-08-11 18:10:14','2024-08-11 18:10:14','985e407c-767d-4af4-91d4-6d251c22b6a4','2006-06-01 04:00:00','Matrix Group International','[{\"col1\":\"Front-End Developer\",\"col2\":\"2006-06-01 04:00:00\",\"col3\":\"2009-11-01 04:00:00\"}]','https://www.matrixgroup.net/','<ul><li>Built websites based on design files using standards compliant HTML, CSS, and JavaScript</li>\n<li>Implemented and extended custom ColdFusion CMS</li>\n<li>Implemented ExpressionEngine CMS</li>\n</ul>');
commit;

--
-- Dumping data for table `craft_matrixcontent_facts`
--

set autocommit=0;
INSERT INTO `craft_matrixcontent_facts` VALUES (1,13,'<p>I guess I have to have one of these pages &#x1f937;‍♂️, so here we go.</p>','2014-01-18 21:42:11','2024-04-16 17:52:15','3f2a5d3e-3975-462d-9f59-f529df8d5c31',1),(2,14,'<p>I live in sunny Charleston, SC with my wife &#x1f46b;, son &#x1f466;, and dogs Kai and Newman &#x1f436;.</p>','2014-01-18 21:42:11','2024-04-16 17:52:15','03c45264-2f9f-4ea0-8706-3d5bf3fe04d1',1),(3,15,'<p>My beautiful matte black Harley Davidson Iron 883 &#x1f3cd;️ is my preferred method of transportation on sunny days.</p>','2014-01-18 21:42:11','2024-04-16 17:52:15','8dc08a0e-e9b9-4624-a8f6-0de70f0f0f08',1),(4,16,'<p>I spend a lot of free time playing basketball ⛹️.</p>','2014-01-18 21:42:11','2024-04-16 17:52:15','b711a95d-2950-4261-bd0c-7482746c48ea',1),(6,852,'<p>As much as possible, I love to cook!</p>','2017-10-02 18:57:25','2024-04-16 17:52:15','59aaf4cd-e4e8-46d8-8f76-11178244de0e',1),(7,862,'<p>I guess I have to have one of these pages. So this is me summed up in a few pictures and sentences.</p>','2019-10-09 15:56:07','2019-10-09 15:56:07','aa749d66-2016-409f-90a2-bdfe0667b29d',1),(8,863,'<p>I live in sunny Charleston, SC with my furry little dude Newman.</p>','2019-10-09 15:56:07','2019-10-09 15:56:07','1b3b9253-adcc-4b1c-86fe-9533621904f9',1),(9,864,'<p>My beautiful matte black Harley Davidson Iron 883 is my preferred method of transportation on sunny days.</p>','2019-10-09 15:56:07','2019-10-09 15:56:07','e10f8a58-fca0-448c-b25d-5577c42eb23e',1),(10,865,'<p>I spend a lot of free time playing basketball.</p>','2019-10-09 15:56:07','2019-10-09 15:56:07','0fae563f-abb5-4d94-919c-163ed9536187',1),(11,866,'<p>As much as possible, I love to cook!</p>','2019-10-09 15:56:07','2019-10-09 15:56:07','c8ccf535-fbfb-46bd-a609-28850c918a88',1),(12,868,'<p>I guess I have to have one of these pages. So this is me summed up in a few pictures and sentences.</p>','2019-10-09 15:56:08','2019-10-09 15:56:08','55097550-e2c2-4004-b67d-1352b0b37c36',1),(13,869,'<p>I live in sunny Charleston, SC with my furry little dude Newman.</p>','2019-10-09 15:56:08','2019-10-09 15:56:08','0aa9810f-ebe5-4188-adf4-011e4cabd679',1),(14,870,'<p>My beautiful matte black Harley Davidson Iron 883 is my preferred method of transportation on sunny days.</p>','2019-10-09 15:56:08','2019-10-09 15:56:08','951a6024-b0ef-44c4-995a-895a38880b04',1),(15,871,'<p>I spend a lot of free time playing basketball.</p>','2019-10-09 15:56:08','2019-10-09 15:56:08','14a96831-fa0e-496b-93fa-48cac70962af',1),(16,872,'<p>As much as possible, I love to cook!</p>','2019-10-09 15:56:08','2019-10-09 15:56:08','4bdae174-350d-42af-bec2-b956eacd1f25',1),(17,894,'<p>I guess I have to have one of these pages. So this is me summed up in a few pictures and sentences.</p>','2019-10-09 16:40:22','2019-10-09 16:40:23','5df23882-d192-4e8d-8101-0c74e8b20de5',1),(18,895,'<p>I live in sunny Charleston, SC with my furry little dude Newman.</p>','2019-10-09 16:40:22','2019-10-09 16:40:23','4cfce51f-fed0-45cb-95c1-b04944568f09',1),(19,896,'<p>My beautiful matte black Harley Davidson Iron 883 is my preferred method of transportation on sunny days.</p>','2019-10-09 16:40:22','2019-10-09 16:40:23','34378cff-71b0-42aa-8b6a-45a9b2516056',1),(20,897,'<p>I spend a lot of free time playing basketball.</p>','2019-10-09 16:40:22','2019-10-09 16:40:23','07650079-e08d-4ad1-949b-f5c64b4258af',1),(21,898,'<p>As much as possible, I love to cook!</p>','2019-10-09 16:40:22','2019-10-09 16:40:23','4ff93071-72f2-4ae3-86f5-77f98c186655',1),(22,900,'<p>I guess I have to have one of these pages. So this is me summed up in a few pictures and sentences.</p>','2019-10-09 16:40:23','2019-10-09 16:40:23','d4c58cdb-d21f-4c69-a0e9-9836c97494b3',1),(23,901,'<p>I live in sunny Charleston, SC with my furry little dude Newman.</p>','2019-10-09 16:40:23','2019-10-09 16:40:23','d7ca4b03-0706-4409-87f2-18a772692e43',1),(24,902,'<p>My beautiful matte black Harley Davidson Iron 883 is my preferred method of transportation on sunny days.</p>','2019-10-09 16:40:23','2019-10-09 16:40:23','ee7d03f4-e254-4fbe-a699-3c44eedea568',1),(25,903,'<p>I spend a lot of free time playing basketball.</p>','2019-10-09 16:40:23','2019-10-09 16:40:23','e27eca20-4f25-4730-a220-db1a098ee0c9',1),(26,904,'<p>As much as possible, I love to cook!</p>','2019-10-09 16:40:23','2019-10-09 16:40:23','7b45d708-4293-4c5c-9e20-e8c0e4f0e35b',1),(27,906,'<p>I guess I have to have one of these pages. So this is me summed up in a few pictures and sentences.</p>','2019-10-09 16:40:23','2019-10-09 16:40:23','81aa122f-cddb-45a1-b33b-74653a92b370',1),(28,907,'<p>I live in sunny Charleston, SC with my furry little dude Newman.</p>','2019-10-09 16:40:23','2019-10-09 16:40:23','823003b9-1f1d-4652-9e43-4232ffd89b15',1),(29,908,'<p>My beautiful matte black Harley Davidson Iron 883 is my preferred method of transportation on sunny days.</p>','2019-10-09 16:40:23','2019-10-09 16:40:23','83997fc7-2d2b-403f-b239-12a3faf5ad4b',1),(30,909,'<p>I spend a lot of free time playing basketball.</p>','2019-10-09 16:40:23','2019-10-09 16:40:23','58038bfb-8375-4dc0-b960-917569aa9f75',1),(31,910,'<p>As much as possible, I love to cook!</p>','2019-10-09 16:40:23','2019-10-09 16:40:23','213b7c68-6736-43c9-8f87-8720244f4ffb',1),(32,912,'<p>I guess I have to have one of these pages. So this is me summed up in a few pictures and sentences.</p>','2019-10-09 16:40:23','2019-10-09 16:40:24','1d2950a5-214a-4b3a-ad38-66f56dc9ce27',1),(33,913,'<p>I live in sunny Charleston, SC with my furry little dude Newman.</p>','2019-10-09 16:40:24','2019-10-09 16:40:24','b6ce7d4b-1024-400b-a2e3-529eadce7c1f',1),(34,914,'<p>My beautiful matte black Harley Davidson Iron 883 is my preferred method of transportation on sunny days.</p>','2019-10-09 16:40:24','2019-10-09 16:40:24','f4d9fced-58be-441c-aae7-86f4a1ffb7af',1),(35,915,'<p>I spend a lot of free time playing basketball.</p>','2019-10-09 16:40:24','2019-10-09 16:40:24','7aaa626a-1a4f-445d-ab6f-983af3f64fb4',1),(36,916,'<p>As much as possible, I love to cook!</p>','2019-10-09 16:40:24','2019-10-09 16:40:24','0fe76b18-5075-4081-8676-581d516f1d74',1),(37,918,'<p>I guess I have to have one of these pages. So this is me summed up in a few pictures and sentences.</p>','2019-10-09 16:40:24','2019-10-09 16:40:24','94768dd3-23c2-433c-b187-a90f616d4120',1),(38,919,'<p>I live in sunny Charleston, SC with my furry little dude Newman.</p>','2019-10-09 16:40:24','2019-10-09 16:40:24','314da484-60c1-4e20-822e-e8f39f133c23',1),(39,920,'<p>My beautiful matte black Harley Davidson Iron 883 is my preferred method of transportation on sunny days.</p>','2019-10-09 16:40:24','2019-10-09 16:40:24','03a414f2-5b22-4932-8a60-80f831e174d8',1),(40,921,'<p>I spend a lot of free time playing basketball.</p>','2019-10-09 16:40:24','2019-10-09 16:40:24','8e6ff3ef-c74d-454f-a2cf-941967e798a9',1),(41,922,'<p>As much as possible, I love to cook!</p>','2019-10-09 16:40:24','2019-10-09 16:40:24','51eb2cc6-076f-4d2f-ad0c-d0ca625fccc2',1),(42,924,'<p>I guess I have to have one of these pages. So this is me summed up in a few pictures and sentences.</p>','2019-10-09 16:40:24','2019-10-09 16:40:24','3de521ab-0d7e-4965-95cb-0aad9b4936b2',1),(43,925,'<p>I live in sunny Charleston, SC with my furry little dude Newman.</p>','2019-10-09 16:40:24','2019-10-09 16:40:24','ed5d642a-1f89-41b5-bd02-7644e6d903ed',1),(44,926,'<p>My beautiful matte black Harley Davidson Iron 883 is my preferred method of transportation on sunny days.</p>','2019-10-09 16:40:24','2019-10-09 16:40:24','b9f7e18e-b766-4085-b0a4-9ae77c6d928c',1),(45,927,'<p>I spend a lot of free time playing basketball.</p>','2019-10-09 16:40:24','2019-10-09 16:40:24','c4d9daa4-44ff-442c-bb4c-51231ad53516',1),(46,928,'<p>As much as possible, I love to cook!</p>','2019-10-09 16:40:24','2019-10-09 16:40:24','f4f54cc4-aba6-4698-9654-00e240f5c1ef',1),(47,930,'<p>I guess I have to have one of these pages. So this is me summed up in a few pictures and sentences.</p>','2019-10-09 16:40:24','2019-10-09 16:40:24','610af7aa-6f3b-4b83-8838-43d5caed5d96',1),(48,931,'<p>I live in sunny Charleston, SC with my furry little dude Newman.</p>','2019-10-09 16:40:24','2019-10-09 16:40:24','8c22a864-0186-4345-8c0a-1b59d64a7574',1),(49,932,'<p>My beautiful matte black Harley Davidson Iron 883 is my preferred method of transportation on sunny days.</p>','2019-10-09 16:40:24','2019-10-09 16:40:25','f1f27295-eb62-4ca3-a51d-cbeceffab6b8',1),(50,933,'<p>I spend a lot of free time playing basketball.</p>','2019-10-09 16:40:24','2019-10-09 16:40:25','7453f6c0-a218-4542-b383-ce5f31e8dcdc',1),(51,934,'<p>As much as possible, I love to cook!</p>','2019-10-09 16:40:24','2019-10-09 16:40:25','62f47fe9-91dd-41d8-ba5c-8781b5e0383a',1),(52,936,'<p>I guess I have to have one of these pages. So this is me summed up in a few pictures and sentences.</p>','2019-10-09 16:40:25','2019-10-09 16:40:25','544168b2-3ef8-4503-a8e3-a54b31aadf4c',1),(53,937,'<p>I live in sunny Charleston, SC with my furry little dude Newman.</p>','2019-10-09 16:40:25','2019-10-09 16:40:25','be7bdd5a-d39e-4cb3-8892-7366b10911fa',1),(54,938,'<p>My beautiful matte black Harley Davidson Iron 883 is my preferred method of transportation on sunny days.</p>','2019-10-09 16:40:25','2019-10-09 16:40:25','9e4d402f-a287-49e8-8cea-da592840f853',1),(55,939,'<p>I spend a lot of free time playing basketball.</p>','2019-10-09 16:40:25','2019-10-09 16:40:25','e0e4081c-85e7-4355-a468-2ea97227528c',1),(56,940,'<p>As much as possible, I love to cook!</p>','2019-10-09 16:40:25','2019-10-09 16:40:25','af41c2ec-d4c4-4713-be33-35bde648954c',1),(57,942,'<p>I guess I have to have one of these pages. So this is me summed up in a few pictures and sentences.</p>','2019-10-09 16:40:25','2019-10-09 16:40:25','a49110d1-264b-46ac-bf83-62b2cee4c4bf',1),(58,943,'<p>I live in sunny Charleston, SC with my furry little dude Newman.</p>','2019-10-09 16:40:25','2019-10-09 16:40:25','5e6dc1e7-0d41-4d55-8cf5-39245c12aef7',1),(59,944,'<p>My beautiful matte black Harley Davidson Iron 883 is my preferred method of transportation on sunny days.</p>','2019-10-09 16:40:25','2019-10-09 16:40:25','3147b5be-1158-44bd-b79b-d815a64ce3c3',1),(60,945,'<p>I spend a lot of free time playing basketball.</p>','2019-10-09 16:40:25','2019-10-09 16:40:25','82791f76-de18-4f67-a54c-4e318c08322a',1),(61,946,'<p>As much as possible, I love to cook!</p>','2019-10-09 16:40:25','2019-10-09 16:40:25','ed9852b6-f9f5-4c98-9f1a-36eaf0e6f421',1),(62,948,'<p>I guess I have to have one of these pages. So this is me summed up in a few pictures and sentences.</p>','2019-10-09 16:40:25','2019-10-09 16:40:25','55190acb-c552-46cc-b493-d9485796d0f7',1),(63,949,'<p>I live in sunny Charleston, SC with my furry little dude Newman.</p>','2019-10-09 16:40:25','2019-10-09 16:40:25','212aaaa5-73d6-4663-b11b-e89ec5f0e9db',1),(64,950,'<p>My beautiful matte black Harley Davidson Iron 883 is my preferred method of transportation on sunny days.</p>','2019-10-09 16:40:25','2019-10-09 16:40:25','ab14fe92-87c5-4220-adf6-039f1cfa66ef',1),(65,951,'<p>I spend a lot of free time playing basketball.</p>','2019-10-09 16:40:25','2019-10-09 16:40:25','b508e031-1e00-433a-a679-bba3991783fe',1),(66,952,'<p>As much as possible, I love to cook!</p>','2019-10-09 16:40:25','2019-10-09 16:40:25','f8fc7341-3636-4e38-ad3e-e0eb9cb29b17',1),(67,954,'<p>I guess I have to have one of these pages. So this is me summed up in a few pictures and sentences.</p>','2019-10-09 16:40:26','2019-10-09 16:40:26','00149031-613b-4ce3-b937-1f074b955546',1),(68,955,'<p>I live in sunny Charleston, SC with my furry little dude Newman.</p>','2019-10-09 16:40:26','2019-10-09 16:40:26','e6f6962d-2991-4030-96bc-57af8ada3122',1),(69,956,'<p>My beautiful matte black Harley Davidson Iron 883 is my preferred method of transportation on sunny days.</p>','2019-10-09 16:40:26','2019-10-09 16:40:26','313de0df-597c-425d-892c-1f6194c39c29',1),(70,957,'<p>I spend a lot of free time playing basketball.</p>','2019-10-09 16:40:26','2019-10-09 16:40:26','90c85e3c-5485-426a-91bf-28448a26c6ed',1),(71,958,'<p>As much as possible, I love to cook!</p>','2019-10-09 16:40:26','2019-10-09 16:40:26','b8bb8a21-4b17-44bd-ad43-ddea95af2adf',1),(72,960,'<p>I guess I have to have one of these pages. So this is me summed up in a few pictures and sentences.</p>','2019-10-09 16:40:26','2019-10-09 16:40:26','01f89cef-5176-423d-b0f7-a0b0c8cc8dd3',1),(73,961,'<p>I live in sunny Charleston, SC with my furry little dude Newman.</p>','2019-10-09 16:40:26','2019-10-09 16:40:26','68d896b7-edeb-472c-873e-56753c50538f',1),(74,962,'<p>My beautiful matte black Harley Davidson Iron 883 is my preferred method of transportation on sunny days.</p>','2019-10-09 16:40:26','2019-10-09 16:40:26','4782999f-7eac-40c6-9caf-ee15df803d82',1),(75,963,'<p>I spend a lot of free time playing basketball.</p>','2019-10-09 16:40:26','2019-10-09 16:40:26','cfe45e6d-cd1e-4879-adc3-c981f10feb32',1),(76,964,'<p>As much as possible, I love to cook!</p>','2019-10-09 16:40:26','2019-10-09 16:40:26','30e1b99f-b18c-4461-9638-0f70bfa5cf80',1),(77,1279,'<p>I guess I have to have one of these pages. So this is me summed up in a few pictures and sentences.</p>','2019-10-09 16:40:43','2019-10-09 16:40:43','aa3f04f1-fe18-4f16-83ec-44d874923986',1),(78,1280,'<p>I live in sunny Charleston, SC with my furry little dude Newman.</p>','2019-10-09 16:40:43','2019-10-09 16:40:43','a1e83883-ba59-48a9-9e71-710230fe34f5',1),(79,1281,'<p>My beautiful matte black Harley Davidson Iron 883 is my preferred method of transportation on sunny days.</p>','2019-10-09 16:40:43','2019-10-09 16:40:43','42a7642e-8453-4bc8-960c-27ddc617bf21',1),(80,1282,'<p>I spend a lot of free time playing basketball.</p>','2019-10-09 16:40:43','2019-10-09 16:40:43','9f7eb458-5bf6-4e7c-a8e0-05ff201fd07d',1),(81,1283,'<p>As much as possible, I love to cook!</p>','2019-10-09 16:40:43','2019-10-09 16:40:43','71a6c016-811e-484b-a41f-ecc2e0fbed87',1),(112,2048,'<p>I guess I have to have one of these pages. So this is me summed up in a few pictures and sentences.</p>','2020-03-18 20:02:26','2020-03-18 20:02:26','404b8d90-d0fd-4d49-a07d-f0f0d903db2e',1),(113,2049,'<p>I live in sunny Charleston, SC with my furry little dude Newman.</p>','2020-03-18 20:02:26','2020-03-18 20:02:26','723f79f0-5fe1-4597-8b91-00e57ae735e3',1),(114,2050,'<p>My beautiful matte black Harley Davidson Iron 883 is my preferred method of transportation on sunny days.</p>','2020-03-18 20:02:27','2020-03-18 20:02:27','02e8f138-6bb5-48b8-80b2-5f18af18c867',1),(115,2051,'<p>I spend a lot of free time playing basketball.</p>','2020-03-18 20:02:27','2020-03-18 20:02:27','108377b4-0558-41fd-9cc7-b6b418034ef4',1),(116,2052,'<p>As much as possible, I love to cook!</p>','2020-03-18 20:02:27','2020-03-18 20:02:27','42228461-ba60-4ddc-be27-f19cc922e559',1),(117,2063,'<p>I guess I have to have one of these pages. So this is me summed up in a few pictures and sentences.</p>','2020-08-10 21:12:18','2020-08-10 21:12:18','38bb8175-53d7-41d8-95b7-58b2a60b698b',1),(118,2064,'<p>I live in sunny Charleston, SC with my furry little dude Newman.</p>','2020-08-10 21:12:18','2020-08-10 21:12:18','789168d5-e67e-4425-a8a9-0096a3ddddc8',1),(119,2065,'<p>My beautiful matte black Harley Davidson Iron 883 is my preferred method of transportation on sunny days.</p>','2020-08-10 21:12:18','2020-08-10 21:12:18','fdcddbd3-7954-46e2-b834-82d8c05e84f1',1),(120,2066,'<p>I spend a lot of free time playing basketball.</p>','2020-08-10 21:12:18','2020-08-10 21:12:18','bb9512e4-21a7-4a1f-8a1d-95496939afe7',1),(121,2067,'<p>As much as possible, I love to cook!</p>','2020-08-10 21:12:18','2020-08-10 21:12:18','d327a8cb-8908-447b-bcf6-97e6175c29d7',1),(122,2071,'<p>I guess I have to have one of these pages. So this is me summed up in a few pictures and sentences.</p>','2020-08-10 21:12:19','2020-08-10 21:12:19','b05a4679-c5cf-49c2-905a-874d7f699fc3',1),(123,2072,'<p>I live in sunny Charleston, SC with my furry little dude Newman.</p>','2020-08-10 21:12:19','2020-08-10 21:12:19','982de47b-dde9-46f3-ad4d-37662c230387',1),(124,2073,'<p>My beautiful matte black Harley Davidson Iron 883 is my preferred method of transportation on sunny days.</p>','2020-08-10 21:12:19','2020-08-10 21:12:19','740e488a-c6e1-452a-9e28-0494824c89c5',1),(125,2074,'<p>I spend a lot of free time playing basketball.</p>','2020-08-10 21:12:19','2020-08-10 21:12:19','6c4bc2c8-b04a-4808-b3db-c62dcb3e2e20',1),(126,2075,'<p>As much as possible, I love to cook!</p>','2020-08-10 21:12:19','2020-08-10 21:12:19','17b78bbb-f01b-427a-87df-b848b660f719',1),(127,2080,'<p>I guess I have to have one of these pages. So this is me summed up in a few pictures and sentences.</p>','2021-02-19 17:56:59','2021-02-19 17:56:59','4508f191-db95-4f2b-b44c-2ea4d8063631',1),(128,2081,'<p>I live in sunny Charleston, SC with my furry little dude Newman.</p>','2021-02-19 17:56:59','2021-02-19 17:56:59','cc542afa-7d0b-40b5-acaf-f74ec8d39faa',1),(129,2082,'<p>My beautiful matte black Harley Davidson Iron 883 is my preferred method of transportation on sunny days.</p>','2021-02-19 17:56:59','2021-02-19 17:56:59','cb040391-f1d6-4240-9b64-a7160d197a2e',1),(130,2083,'<p>I spend a lot of free time playing basketball.</p>','2021-02-19 17:56:59','2021-02-19 17:56:59','128c08e4-61c9-456d-8b18-e92d90c70741',1),(131,2084,'<p>As much as possible, I love to cook!</p>','2021-02-19 17:56:59','2021-02-19 17:56:59','ac13dac6-9064-452a-86d6-c0d7b838175c',1),(137,2109,'<p>I guess I have to have one of these pages. So this is me summed up in a few pictures and sentences.</p>','2022-01-15 13:49:05','2022-01-15 13:49:05','2c20c002-8f02-4ea5-8d21-a2aef7a0fe95',1),(138,2110,'<p>I live in sunny Charleston, SC with my furry little dude Newman.</p>','2022-01-15 13:49:05','2022-01-15 13:49:05','9ab53fc4-0fda-45ae-beb2-24cdbdb42af2',1),(139,2111,'<p>My beautiful matte black Harley Davidson Iron 883 is my preferred method of transportation on sunny days.</p>','2022-01-15 13:49:05','2022-01-15 13:49:05','3dfba0db-342b-40e1-b0b9-a0c9128d6856',1),(140,2112,'<p>I spend a lot of free time playing basketball.</p>','2022-01-15 13:49:05','2022-01-15 13:49:05','fe369c00-5a2e-4957-b440-d62addc9732e',1),(141,2113,'<p>As much as possible, I love to cook!</p>','2022-01-15 13:49:05','2022-01-15 13:49:05','21d88b95-5fd3-4ed0-aa08-71ae91edb9c0',1),(147,2122,'<p>I guess I have to have one of these pages. So this is me summed up in a few pictures and sentences.</p>','2022-01-15 13:52:53','2022-01-15 13:52:53','5bc4a273-6f3d-4623-b222-2df05cc3662e',1),(148,2123,'<p>I live in sunny Charleston, SC with my furry little dude Newman.</p>','2022-01-15 13:52:53','2022-01-15 13:52:53','867f863e-8ce5-4687-a264-cff3360c3ff4',1),(149,2124,'<p>My beautiful matte black Harley Davidson Iron 883 is my preferred method of transportation on sunny days.</p>','2022-01-15 13:52:53','2022-01-15 13:52:53','1a561d72-6d1a-44f4-a878-b6c51cc186bc',1),(150,2125,'<p>I spend a lot of free time playing basketball.</p>','2022-01-15 13:52:53','2022-01-15 13:52:53','01aa67d3-4880-4c1f-9fa4-327b3506b918',1),(151,2126,'<p>As much as possible, I love to cook!</p>','2022-01-15 13:52:53','2022-01-15 13:52:53','8adda765-cbf8-4daa-82e5-d8ced6221015',1),(157,2135,'<p>I guess I have to have one of these pages. So this is me summed up in a few pictures and sentences.</p>','2022-01-15 13:54:37','2022-01-15 13:54:37','e5bb9aee-dfdc-4ca2-8ae7-85ba074feab6',1),(158,2136,'<p>I live in sunny Charleston, SC with my furry little dude Newman.</p>','2022-01-15 13:54:37','2022-01-15 13:54:37','3e92f6cb-d818-4a5a-86fb-f9135b41c0f5',1),(159,2137,'<p>My beautiful matte black Harley Davidson Iron 883 is my preferred method of transportation on sunny days.</p>','2022-01-15 13:54:37','2022-01-15 13:54:37','d1ef04d0-f153-4d71-92e7-9ed552d54242',1),(160,2138,'<p>I spend a lot of free time playing basketball.</p>','2022-01-15 13:54:37','2022-01-15 13:54:37','970d9f22-db18-43d2-8cfe-242287f0a818',1),(161,2139,'<p>As much as possible, I love to cook!</p>','2022-01-15 13:54:37','2022-01-15 13:54:37','b7d60909-5752-49e8-a3f2-3d361d440ca9',1),(167,2451,'<p>I guess I have to have one of these pages. So this is me summed up in a few pictures and sentences.</p>','2022-11-16 21:26:00','2022-11-16 21:26:00','89db7509-a2df-47d8-9884-206cd73af60d',1),(168,2452,'<p>I live in sunny Charleston, SC with my furry little dude Newman.</p>','2022-11-16 21:26:00','2022-11-16 21:26:00','5983373c-56b2-4221-9e53-9cef42e335e1',1),(169,2453,'<p>My beautiful matte black Harley Davidson Iron 883 is my preferred method of transportation on sunny days.</p>','2022-11-16 21:26:00','2022-11-16 21:26:00','08f43ca1-a89e-4905-9e80-6c84cc34f28c',1),(170,2454,'<p>I spend a lot of free time playing basketball.</p>','2022-11-16 21:26:00','2022-11-16 21:26:00','1272b018-dc95-4cc4-96e3-f2d4c583658c',1),(171,2455,'<p>As much as possible, I love to cook!</p>','2022-11-16 21:26:00','2022-11-16 21:26:00','8fec4646-bb19-4b2d-ad4b-da4bf7e819e1',1),(177,2464,'<p>I guess I have to have one of these pages. So this is me summed up in a few pictures and sentences.</p>','2022-11-16 21:27:31','2022-11-16 21:27:31','79712c83-6ed9-4cee-83f0-1e231f1fab81',1),(178,2465,'<p>I live in sunny Charleston, SC with my furry little dude Newman.</p>','2022-11-16 21:27:31','2022-11-16 21:27:31','04fc5cef-fd3e-46ac-88e9-d837d7a8f0ce',1),(179,2466,'<p>My beautiful matte black Harley Davidson Iron 883 is my preferred method of transportation on sunny days.</p>','2022-11-16 21:27:31','2022-11-16 21:27:31','f07ab968-31a9-4a7d-b24a-9b0ebc34b10d',1),(180,2467,'<p>I spend a lot of free time playing basketball.</p>','2022-11-16 21:27:31','2022-11-16 21:27:31','b29895d9-140e-4d1b-b7e5-197ca886ab8d',1),(181,2468,'<p>As much as possible, I love to cook!</p>','2022-11-16 21:27:31','2022-11-16 21:27:31','d853ea64-9089-4a8b-95fe-2b3635dc7718',1),(187,3426,'<p>I guess I have to have one of these pages. So this is me summed up in a few pictures and sentences.</p>','2024-02-09 20:55:17','2024-02-09 20:55:17','2312b0b1-41e1-4286-8f4f-3f96439a95cc',1),(188,3427,'<p>I live in sunny Charleston, SC with my furry little dude Newman.</p>','2024-02-09 20:55:17','2024-02-09 20:55:17','cef97555-5a2f-481c-8fd7-0e314cf9e998',1),(189,3428,'<p>My beautiful matte black Harley Davidson Iron 883 is my preferred method of transportation on sunny days.</p>','2024-02-09 20:55:17','2024-02-09 20:55:17','86158f33-8a95-489f-9920-05f2e19550b2',1),(190,3429,'<p>I spend a lot of free time playing basketball.</p>','2024-02-09 20:55:17','2024-02-09 20:55:17','3c7bd144-7e12-438b-ad13-65ea508ed53f',1),(191,3430,'<p>As much as possible, I love to cook!</p>','2024-02-09 20:55:17','2024-02-09 20:55:17','9823ea12-4220-4ce1-9ad8-b5a69d532078',1),(192,3584,'<p>I guess I have to have one of these pages. So this is me summed up in a few pictures and sentences.</p>','2024-04-15 18:28:06','2024-04-15 18:28:06','14ab3f50-58b8-4eff-8950-762a4dab258a',1),(193,3585,'<p>I live in sunny Charleston, SC with my furry little dude Newman.</p>','2024-04-15 18:28:06','2024-04-15 18:28:06','58132a95-8c7d-4307-8990-f15891307d46',1),(194,3586,'<p>My beautiful matte black Harley Davidson Iron 883 is my preferred method of transportation on sunny days.</p>','2024-04-15 18:28:06','2024-04-15 18:28:06','853a7c56-ac13-43e5-8802-14f4cef28da4',1),(195,3587,'<p>I spend a lot of free time playing basketball.</p>','2024-04-15 18:28:06','2024-04-15 18:28:06','0cbf73c2-e6a5-4ca8-a88e-02e0b012a93a',1),(196,3588,'<p>As much as possible, I love to cook!</p>','2024-04-15 18:28:06','2024-04-15 18:28:06','834c70ae-346f-4953-b786-3d16f656ca69',1),(197,3590,'<p>I guess I have to have one of these pages. So this is me summed up in a few pictures and sentences.</p>','2024-04-15 18:28:06','2024-04-15 18:28:06','63f72768-0418-4d4b-8099-6083a8f43452',1),(198,3591,'<p>I live in sunny Charleston, SC with my furry little dude Newman.</p>','2024-04-15 18:28:06','2024-04-15 18:28:06','30de6222-6a26-421e-80d8-e6e4e2836921',1),(199,3592,'<p>My beautiful matte black Harley Davidson Iron 883 is my preferred method of transportation on sunny days.</p>','2024-04-15 18:28:06','2024-04-15 18:28:06','e11d1845-5916-4cbc-9288-46c3aadca171',1),(200,3593,'<p>I spend a lot of free time playing basketball.</p>','2024-04-15 18:28:06','2024-04-15 18:28:06','06094c10-1938-4167-8319-2de8ae46b04e',1),(201,3594,'<p>As much as possible, I love to cook!</p>','2024-04-15 18:28:06','2024-04-15 18:28:06','e523e07e-6b47-4ad9-95e2-506f8527be7b',1),(202,3596,'<p>I guess I have to have one of these pages. So this is me summed up in a few pictures and sentences.</p>','2024-04-15 18:28:07','2024-04-15 18:28:07','fe234ee3-27f1-4067-832c-cac50536a116',1),(203,3597,'<p>I live in sunny Charleston, SC with my furry little dude Newman.</p>','2024-04-15 18:28:07','2024-04-15 18:28:07','33db1980-ca44-4f35-861a-e9ae07af41d6',1),(204,3598,'<p>My beautiful matte black Harley Davidson Iron 883 is my preferred method of transportation on sunny days.</p>','2024-04-15 18:28:07','2024-04-15 18:28:07','d55ef3f0-7c42-4a22-acc1-6873b9ebbd51',1),(205,3599,'<p>I spend a lot of free time playing basketball.</p>','2024-04-15 18:28:07','2024-04-15 18:28:07','15052236-0ea7-4b98-9af9-ed21cea19092',1),(206,3600,'<p>As much as possible, I love to cook!</p>','2024-04-15 18:28:07','2024-04-15 18:28:07','d47aea6d-ae34-487b-a71b-f1a3f7e8ddaa',1),(212,3626,'<p>I guess I have to have one of these pages. So this is me summed up in a few pictures and sentences.</p>','2024-04-15 18:36:12','2024-04-15 18:36:12','008ac258-8716-4575-b516-4ee7936bef35',1),(213,3627,'<p>I live in sunny Charleston, SC with my furry little dude Newman.</p>','2024-04-15 18:36:12','2024-04-15 18:36:12','4fc360ac-8f77-48ff-9db8-23ca73dcfd97',1),(214,3628,'<p>My beautiful matte black Harley Davidson Iron 883 is my preferred method of transportation on sunny days.</p>','2024-04-15 18:36:12','2024-04-15 18:36:12','0a21cd1d-5103-4f7f-b3bd-1b8268b56163',1),(215,3629,'<p>I spend a lot of free time playing basketball.</p>','2024-04-15 18:36:12','2024-04-15 18:36:12','3e84f7be-e2d7-4025-b243-5c2d54d7cb4f',1),(216,3630,'<p>As much as possible, I love to cook!</p>','2024-04-15 18:36:12','2024-04-15 18:36:12','ec44d77e-3de1-4282-8b41-5053e8882bf9',1),(222,3675,'<p>I guess I have to have one of these pages. So this is me summed up in a few pictures and sentences.</p>','2024-04-15 18:39:57','2024-04-15 18:39:57','0630e290-b9db-400a-9d1d-4ff46614fdaa',1),(223,3676,'<p>I live in sunny Charleston, SC with my furry little dude Newman.</p>','2024-04-15 18:39:57','2024-04-15 18:39:57','1f0c425e-de86-4473-92a7-704336983c9a',1),(224,3677,'<p>My beautiful matte black Harley Davidson Iron 883 is my preferred method of transportation on sunny days.</p>','2024-04-15 18:39:57','2024-04-15 18:39:57','76f99855-fd10-48b5-9bfd-0cb6df6141be',1),(225,3678,'<p>I spend a lot of free time playing basketball.</p>','2024-04-15 18:39:57','2024-04-15 18:39:57','d1e68ff1-c8e5-4ba2-bc47-570e61ce420f',1),(226,3679,'<p>As much as possible, I love to cook!</p>','2024-04-15 18:39:57','2024-04-15 18:39:57','4d4d8a8b-d69d-406f-946b-0005bd0e8697',1),(232,3704,'<p>I guess I have to have one of these pages. So this is me summed up in a few pictures and sentences.</p>','2024-04-15 18:41:19','2024-04-15 18:41:19','856e7da2-5e78-434d-8e87-a4d7f2b85153',1),(233,3705,'<p>I live in sunny Charleston, SC with my furry little dude Newman.</p>','2024-04-15 18:41:19','2024-04-15 18:41:19','e3f4e43f-8e5b-4fbc-ad5e-fc6d1ad78935',1),(234,3706,'<p>My beautiful matte black Harley Davidson Iron 883 is my preferred method of transportation on sunny days.</p>','2024-04-15 18:41:19','2024-04-15 18:41:19','81b52853-d589-46b9-83aa-dc2e16863c97',1),(235,3707,'<p>I spend a lot of free time playing basketball.</p>','2024-04-15 18:41:19','2024-04-15 18:41:19','9058082f-d00c-4bb7-9863-6e62ed632d5b',1),(236,3708,'<p>As much as possible, I love to cook!</p>','2024-04-15 18:41:19','2024-04-15 18:41:19','522b60ab-2a60-4a68-bdc7-6b410fa2739c',1),(242,3722,'<p>I guess I have to have one of these pages. So this is me summed up in a few pictures and sentences.</p>','2024-04-15 18:43:25','2024-04-15 18:43:25','0629097e-e415-40c6-b5f9-1593e1be0ebe',1),(243,3723,'<p>I live in sunny Charleston, SC with my furry little dude Newman.</p>','2024-04-15 18:43:26','2024-04-15 18:43:26','627a5c59-9d02-4183-a66b-02da6085bad9',1),(244,3724,'<p>My beautiful matte black Harley Davidson Iron 883 is my preferred method of transportation on sunny days.</p>','2024-04-15 18:43:26','2024-04-15 18:43:26','db0d1ca9-a7f8-44c3-adf0-049c52ed66be',1),(245,3725,'<p>I spend a lot of free time playing basketball.</p>','2024-04-15 18:43:26','2024-04-15 18:43:26','bcb1219c-440b-4403-aa83-a1fad08cccfb',1),(246,3726,'<p>As much as possible, I love to cook!</p>','2024-04-15 18:43:26','2024-04-15 18:43:26','85e433ef-6139-49db-ae38-8fac394ad588',1),(252,3740,'<p>I guess I have to have one of these pages. So this is me summed up in a few pictures and sentences.</p>','2024-04-16 15:25:13','2024-04-16 15:25:13','a1cbe8c9-2131-418d-85ed-fcd76abea464',1),(253,3741,'<p>I live in sunny Charleston, SC with my furry little dude Newman.</p>','2024-04-16 15:25:13','2024-04-16 15:25:13','c4831fdf-de44-4883-8041-a64002424066',1),(254,3742,'<p>My beautiful matte black Harley Davidson Iron 883 is my preferred method of transportation on sunny days.</p>','2024-04-16 15:25:13','2024-04-16 15:25:13','40744e7a-25bb-49b7-b687-ffb6a5542823',1),(255,3743,'<p>I spend a lot of free time playing basketball.</p>','2024-04-16 15:25:13','2024-04-16 15:25:13','3e19a03a-5ff7-40ec-9fcc-9a63c14259ba',1),(256,3744,'<p>As much as possible, I love to cook!</p>','2024-04-16 15:25:13','2024-04-16 15:25:13','e523cdf5-f450-4fc3-acd4-9c299bbbf49d',1),(262,3758,'<p>I guess I have to have one of these pages. So this is me summed up in a few pictures and sentences.</p>','2024-04-16 16:57:47','2024-04-16 16:57:47','1f914083-4e85-48a7-80b6-34f2c1c3f58d',1),(263,3759,'<p>I live in sunny Charleston, SC with my wife, son, and dogs Kai and Newman.</p>','2024-04-16 16:57:47','2024-04-16 16:57:47','1fc3b3e0-aa2f-465d-8c4d-1481518ef659',1),(264,3760,'<p>My beautiful matte black Harley Davidson Iron 883 is my preferred method of transportation on sunny days.</p>','2024-04-16 16:57:47','2024-04-16 16:57:47','1244f0b6-ad79-4440-b507-f6f01e434f3f',1),(265,3761,'<p>I spend a lot of free time playing basketball.</p>','2024-04-16 16:57:47','2024-04-16 16:57:47','58767dca-64b0-43e5-87d5-2d8ebfc66058',1),(266,3762,'<p>As much as possible, I love to cook!</p>','2024-04-16 16:57:47','2024-04-16 16:57:47','50dd2f74-ce89-476f-8958-b2740047ca7e',1),(272,3782,'<p>I guess I have to have one of these pages. So this is me summed up in a few pictures and sentences.</p>','2024-04-16 17:03:42','2024-04-16 17:03:42','82b1f6e5-c098-42ca-b49c-2012ee1b77c5',1),(273,3783,'<p>I live in sunny Charleston, SC with my wife, son, and dogs Kai and Newman.</p>','2024-04-16 17:03:42','2024-04-16 17:03:42','26d3ac27-c1e4-4ff5-8e99-0080c3cc4794',1),(274,3784,'<p>My beautiful matte black Harley Davidson Iron 883 is my preferred method of transportation on sunny days.</p>','2024-04-16 17:03:42','2024-04-16 17:03:42','1a9e1140-ed52-43ee-85a7-8e016eab9273',1),(275,3785,'<p>I spend a lot of free time playing basketball.</p>','2024-04-16 17:03:42','2024-04-16 17:03:42','8ae4093d-d87f-4851-b262-9cb1d1fcb56f',1),(276,3786,'<p>As much as possible, I love to cook!</p>','2024-04-16 17:03:42','2024-04-16 17:03:42','d0737d0d-7f74-4891-9c6f-a2a722c79cf4',1),(282,3800,'<p>I guess I have to have one of these pages. So this is me summed up in a few pictures and sentences.</p>','2024-04-16 17:10:04','2024-04-16 17:10:04','d0e0384e-5108-4d4d-ae77-4054791f39ea',1),(283,3801,'<p>I live in sunny Charleston, SC with my wife, son, and dogs Kai and Newman.</p>','2024-04-16 17:10:04','2024-04-16 17:10:04','9c579b9e-668b-4a2d-aa62-b2c94a710ebb',1),(284,3802,'<p>My beautiful matte black Harley Davidson Iron 883 is my preferred method of transportation on sunny days.</p>','2024-04-16 17:10:04','2024-04-16 17:10:04','e6c1fc40-8c85-4921-85c9-461cbb12a8c3',1),(285,3803,'<p>I spend a lot of free time playing basketball.</p>','2024-04-16 17:10:04','2024-04-16 17:10:04','d51f3d1a-f69f-4d58-87f6-e11eebfdef24',1),(286,3804,'<p>As much as possible, I love to cook!</p>','2024-04-16 17:10:04','2024-04-16 17:10:04','44a6dcf3-53b2-44ba-91ea-6196ba8cd2df',1),(292,3818,'<p>I guess I have to have one of these pages. So this is me summed up in a few pictures and sentences.</p>','2024-04-16 17:10:39','2024-04-16 17:10:39','f5d178ce-542e-42ba-b2b2-8d408e02cd76',1),(293,3819,'<p>I live in sunny Charleston, SC with my wife, son, and dogs Kai and Newman.</p>','2024-04-16 17:10:39','2024-04-16 17:10:39','028dc5e0-836c-4d54-8f69-5214c2888689',1),(294,3820,'<p>My beautiful matte black Harley Davidson Iron 883 is my preferred method of transportation on sunny days.</p>','2024-04-16 17:10:39','2024-04-16 17:10:39','a8150c71-658e-4c39-b64b-32758f0aa175',1),(295,3821,'<p>I spend a lot of free time playing basketball.</p>','2024-04-16 17:10:39','2024-04-16 17:10:39','b4656fc8-4626-4ed5-b45a-60235ea5e139',1),(296,3822,'<p>As much as possible, I love to cook!</p>','2024-04-16 17:10:39','2024-04-16 17:10:39','7a5b362a-a8bd-4e17-99a7-6c5273852089',1),(302,3838,'<p>I guess I have to have one of these pages. So this is me summed up in a few pictures and sentences.</p>','2024-04-16 17:16:09','2024-04-16 17:16:09','edc649f7-9b84-4329-9307-ae9218f58bcd',1),(303,3839,'<p>I live in sunny Charleston, SC with my wife, son, and dogs Kai and Newman.</p>','2024-04-16 17:16:09','2024-04-16 17:16:09','17fa8fc2-90c6-4085-af87-ec937ccfda21',1),(304,3840,'<p>My beautiful matte black Harley Davidson Iron 883 is my preferred method of transportation on sunny days.</p>','2024-04-16 17:16:09','2024-04-16 17:16:09','5184a1df-8283-4916-8e90-348f52800c3e',1),(305,3841,'<p>I spend a lot of free time playing basketball.</p>','2024-04-16 17:16:09','2024-04-16 17:16:09','113d06ff-fa53-4373-8d0d-cb3932390817',1),(306,3842,'<p>As much as possible, I love to cook!</p>','2024-04-16 17:16:09','2024-04-16 17:16:09','666c65ac-b047-4ac2-8a84-8fdeaa08a1dd',1),(312,3856,'<p>I guess I have to have one of these pages. So this is me summed up in a few pictures and sentences.</p>','2024-04-16 17:16:26','2024-04-16 17:16:26','222d9bb6-319c-448e-8b36-b1aa6811643a',1),(313,3857,'<p>I live in sunny Charleston, SC with my wife, son, and dogs Kai and Newman.</p>','2024-04-16 17:16:26','2024-04-16 17:16:26','2a0c6ea7-dd4a-4620-96f0-2977135ba837',1),(314,3858,'<p>My beautiful matte black Harley Davidson Iron 883 is my preferred method of transportation on sunny days.</p>','2024-04-16 17:16:26','2024-04-16 17:16:26','ebeafdcd-8ccf-4349-bc12-f50400c721f2',1),(315,3859,'<p>I spend a lot of free time playing basketball.</p>','2024-04-16 17:16:27','2024-04-16 17:16:27','0445e46c-5780-41c4-9b63-e0ac177dbf32',1),(316,3860,'<p>As much as possible, I love to cook!</p>','2024-04-16 17:16:27','2024-04-16 17:16:27','6d835d67-915b-4e37-8f9e-36abe5c99323',1),(322,3875,'<p>I guess I have to have one of these pages. So this is me summed up in a few pictures and sentences.</p>','2024-04-16 17:29:55','2024-04-16 17:29:55','15c1b96d-2e9b-42b6-8c46-b80c1361921b',1),(323,3876,'<p>I live in sunny Charleston, SC with my wife, son, and dogs Kai and Newman.</p>','2024-04-16 17:29:55','2024-04-16 17:29:55','1ca899d3-ae22-4ab8-90aa-99d2b3f84bd0',1),(324,3877,'<p>My beautiful matte black Harley Davidson Iron 883 is my preferred method of transportation on sunny days.</p>','2024-04-16 17:29:55','2024-04-16 17:29:55','0ec1a9c8-a2c8-4839-9bc1-9acc367c6945',1),(325,3878,'<p>I spend a lot of free time playing basketball.</p>','2024-04-16 17:29:55','2024-04-16 17:29:55','f21fa9a8-5702-43c0-807e-a813e339649d',1),(326,3879,'<p>As much as possible, I love to cook!</p>','2024-04-16 17:29:55','2024-04-16 17:29:55','0449668a-8e84-41b3-9710-7dafa663b591',1),(332,3893,'<p>I guess I have to have one of these pages &#x1f937;‍♂️, so this is me &#x1f44b;</p>','2024-04-16 17:50:17','2024-04-16 17:50:17','9c6506bd-6e58-4d81-ab4d-6cb9c71bb873',1),(333,3894,'<p>I live in sunny Charleston, SC with my wife, son, and dogs Kai and Newman.</p>','2024-04-16 17:50:17','2024-04-16 17:50:17','975f92d0-1fa2-41b4-aff4-aa8eff30c808',1),(334,3895,'<p>My beautiful matte black Harley Davidson Iron 883 is my preferred method of transportation on sunny days.</p>','2024-04-16 17:50:17','2024-04-16 17:50:17','10c964d8-0e3d-4b61-bf43-6bcfc9d9e7d0',1),(335,3896,'<p>I spend a lot of free time playing basketball.</p>','2024-04-16 17:50:17','2024-04-16 17:50:17','c56918a3-aebc-42ee-984e-71e8e77ad0fe',1),(336,3897,'<p>As much as possible, I love to cook!</p>','2024-04-16 17:50:17','2024-04-16 17:50:17','33592409-3cc2-4f11-88fc-95c8e906c9e2',1),(342,3911,'<p>&#x1f44b; I guess I have to have one of these pages &#x1f937;‍♂️</p>','2024-04-16 17:50:34','2024-04-16 17:50:34','eac7684e-00d6-4271-acb0-fd5539ab745d',1),(343,3912,'<p>I live in sunny Charleston, SC with my wife, son, and dogs Kai and Newman.</p>','2024-04-16 17:50:34','2024-04-16 17:50:34','5a0d8385-7e04-4726-9f80-c8c50fb33d2e',1),(344,3913,'<p>My beautiful matte black Harley Davidson Iron 883 is my preferred method of transportation on sunny days.</p>','2024-04-16 17:50:34','2024-04-16 17:50:34','b88c5ee6-7e44-4bfe-8db3-09dcc166c5ff',1),(345,3914,'<p>I spend a lot of free time playing basketball.</p>','2024-04-16 17:50:34','2024-04-16 17:50:34','1b6536f2-a5e9-40a1-9b2f-307957fdafc7',1),(346,3915,'<p>As much as possible, I love to cook!</p>','2024-04-16 17:50:34','2024-04-16 17:50:34','8ac13015-7c7e-4578-880e-2c8a2d7e4b5b',1),(352,3929,'<p>&#x1f44b; I guess I have to have one of these pages &#x1f937;‍♂️</p>','2024-04-16 17:51:07','2024-04-16 17:51:07','ed48bbe8-7bb0-430e-8d32-c5477b1a6512',1),(353,3930,'<p>I live in sunny Charleston, SC with my wife &#x1f46b;, son &#x1f466;, and dogs Kai and Newman &#x1f436;.</p>','2024-04-16 17:51:07','2024-04-16 17:51:07','92ed0c03-ba41-477f-9868-f4e6f0622989',1),(354,3931,'<p>My beautiful matte black Harley Davidson Iron 883 is my preferred method of transportation on sunny days.</p>','2024-04-16 17:51:07','2024-04-16 17:51:07','09fb8cd8-9cae-4010-af9b-b4ea250fe745',1),(355,3932,'<p>I spend a lot of free time playing basketball.</p>','2024-04-16 17:51:08','2024-04-16 17:51:08','57c71b4d-45db-48dc-9c3f-4c712dde1adc',1),(356,3933,'<p>As much as possible, I love to cook!</p>','2024-04-16 17:51:08','2024-04-16 17:51:08','51c1dbbf-cf3b-4de8-9c8d-f43ab56af907',1),(362,3947,'<p>&#x1f44b; I guess I have to have one of these pages &#x1f937;‍♂️</p>','2024-04-16 17:51:35','2024-04-16 17:51:35','54f50d69-1dea-4118-85b3-8a661120517c',1),(363,3948,'<p>I live in sunny Charleston, SC with my wife &#x1f46b;, son &#x1f466;, and dogs Kai and Newman &#x1f436;.</p>','2024-04-16 17:51:35','2024-04-16 17:51:35','77d838a0-fbae-487c-a589-cad703912a67',1),(364,3949,'<p>My beautiful matte black Harley Davidson Iron 883 &#x1f3cd;️ is my preferred method of transportation on sunny days.</p>','2024-04-16 17:51:35','2024-04-16 17:51:35','b64d610e-c1e7-43a9-ad99-137cfb178a92',1),(365,3950,'<p>I spend a lot of free time playing basketball ⛹️.</p>','2024-04-16 17:51:35','2024-04-16 17:51:35','7c884b76-57d0-4508-a1c0-24482be83598',1),(366,3951,'<p>As much as possible, I love to cook!</p>','2024-04-16 17:51:35','2024-04-16 17:51:35','c8b3aae7-4c50-4924-bf0d-b6039c0766d9',1),(372,3965,'<p>I guess I have to have one of these pages &#x1f937;‍♂️</p>','2024-04-16 17:51:59','2024-04-16 17:51:59','62a39da5-bc02-4826-9102-3467a963fe59',1),(373,3966,'<p>I live in sunny Charleston, SC with my wife &#x1f46b;, son &#x1f466;, and dogs Kai and Newman &#x1f436;.</p>','2024-04-16 17:51:59','2024-04-16 17:51:59','ad015cab-80b1-412c-ae6a-e82571bd51aa',1),(374,3967,'<p>My beautiful matte black Harley Davidson Iron 883 &#x1f3cd;️ is my preferred method of transportation on sunny days.</p>','2024-04-16 17:51:59','2024-04-16 17:51:59','4a8b7f01-b639-4fdb-b027-9ad1e49d38d0',1),(375,3968,'<p>I spend a lot of free time playing basketball ⛹️.</p>','2024-04-16 17:51:59','2024-04-16 17:51:59','730fa1dd-69a1-41b2-be8f-8fcfa1210029',1),(376,3969,'<p>As much as possible, I love to cook!</p>','2024-04-16 17:51:59','2024-04-16 17:51:59','a35ecbe2-377b-4ba6-8b7f-98802e97cda8',1),(382,3983,'<p>I guess I have to have one of these pages &#x1f937;‍♂️, so here we go.</p>','2024-04-16 17:52:15','2024-04-16 17:52:15','f139a98b-e48b-4cf1-8971-9f064fcda3ca',1),(383,3984,'<p>I live in sunny Charleston, SC with my wife &#x1f46b;, son &#x1f466;, and dogs Kai and Newman &#x1f436;.</p>','2024-04-16 17:52:15','2024-04-16 17:52:15','e636baac-9d11-47e1-a67f-cece82d5abe4',1),(384,3985,'<p>My beautiful matte black Harley Davidson Iron 883 &#x1f3cd;️ is my preferred method of transportation on sunny days.</p>','2024-04-16 17:52:15','2024-04-16 17:52:15','78cfc7e9-12d0-4ca0-9e1f-3310cf929213',1),(385,3986,'<p>I spend a lot of free time playing basketball ⛹️.</p>','2024-04-16 17:52:15','2024-04-16 17:52:15','b12fac4f-8a7a-4326-ae51-a9a9e8532578',1),(386,3987,'<p>As much as possible, I love to cook!</p>','2024-04-16 17:52:15','2024-04-16 17:52:15','f8519909-3937-4ee1-abf1-9c205cd101de',1),(392,4353,'<p>I guess I have to have one of these pages &#x1f937;‍♂️, so here we go.</p>','2024-08-11 18:10:14','2024-08-11 18:10:14','4b23f1e3-a1d7-4ef2-8415-6eb3ee8fb8ce',1),(393,4354,'<p>I live in sunny Charleston, SC with my wife &#x1f46b;, son &#x1f466;, and dogs Kai and Newman &#x1f436;.</p>','2024-08-11 18:10:14','2024-08-11 18:10:14','4fa7105a-cf77-4350-968c-3c6ee0852aca',1),(394,4355,'<p>My beautiful matte black Harley Davidson Iron 883 &#x1f3cd;️ is my preferred method of transportation on sunny days.</p>','2024-08-11 18:10:14','2024-08-11 18:10:14','acfd763f-b14c-454b-8d68-7ba23104654e',1),(395,4356,'<p>I spend a lot of free time playing basketball ⛹️.</p>','2024-08-11 18:10:14','2024-08-11 18:10:14','ff05e862-2cfb-4c10-ac93-2a9cf579bac6',1),(396,4357,'<p>As much as possible, I love to cook!</p>','2024-08-11 18:10:14','2024-08-11 18:10:14','204c4dec-974f-4bba-922b-5e8acd0219c2',1);
commit;

--
