@@ -265,6 +276,7 @@ const FramerMotionFadeInComponent: React.FC = () => {
Here's the code for it The Update
+
+Over the past few years, I've primarily relied on Framer Motion for handling my animations, while incorporating GSAP from time to time, I found it to be somewhat verbose compared to **Framer**, especially in a **React** context.
+
+But, check this out, yesterday **GSAP** introduced the **``useGSAP()``** hook, an addition to easily integrate **GSAP** with **React**.
+
+Prior to this, animating elements involved wrapping them in a **``gsap.Context``** object, then, you had to use the same object's methods like **``.revert()``** or **``.kill()``** within **``useEffect()``** or **``useLayoutEffect()``** cleanup function to avoid memory leaks, depending if you're within an **SSR** context or not, along with a mandatory dependency array that you have to keep track of.
+
+ To do something like
+
+
+You'd probably need to
+ {
+ const container = useRef(null);
+
+ useIsoLayoutEffect(() => {
+ const ctx = gsap.context(() => {
+ const tl = gsap.timeline({ repeat: -1, repeatDelay: 0.5 });
+
+ tl.to('.x', {
+ rotation: 360,
+ duration: 2,
+ borderRadius: 16,
+ translateX: -150,
+ ease: 'power1.inOut',
+ });
+ tl.to('.x', {
+ rotation: -360,
+ duration: 2,
+ borderRadius: 0,
+ translateX: 150,
+ ease: 'power1.inOut',
+ });
+ tl.to('.x', {
+ rotation: 360,
+ duration: 2,
+ borderRadius: 16,
+ translateX: 0,
+ ease: 'power1.inOut',
+ });
+ }, container);
+
+ return () => ctx.revert();
+ }, []);
+
+ return (
+
+
+
+
+
+
+
+ );
+};
+`}
+ language="tsx"
+ showLineNumbers={false}
+/>
+This new hook abstracts away these inconveniences, and obviates the need for explicit cleanup.
+ So the same Logic above can be written as
+ {
+ const container = useRef(null);
+
+ useGSAP(
+ () => {
+ const tl = gsap.timeline({ repeat: -1, repeatDelay: 0.5 });
+ tl.to('.x', {
+ rotation: 360,
+ duration: 2,
+ borderRadius: 16,
+ translateX: -150,
+ ease: 'power1.inOut',
+ });
+ tl.to('.x', {
+ rotation: -360,
+ duration: 2,
+ borderRadius: 0,
+ translateX: 150,
+ ease: 'power1.inOut',
+ });
+ tl.to('.x', {
+ rotation: 360,
+ duration: 2,
+ borderRadius: 16,
+ translateX: 0,
+ ease: 'power1.inOut',
+ });
+ },
+ { scope: container}
+ );
+ return (
+
+
+
+
+
+
+
+ );
+};
+`}
+ language="tsx"
+ showLineNumbers={false}
+/>
+I like this update. I might start using **GSAP** even more now
diff --git a/public/blogs/jest-and-playwright-conflicts-solution.mdx b/public/blogs/jest-and-playwright-conflicts-solution.mdx
new file mode 100644
index 00000000..f1d99492
--- /dev/null
+++ b/public/blogs/jest-and-playwright-conflicts-solution.mdx
@@ -0,0 +1,13 @@
+---
+title: Jest and Playwright
+seoTitle: How to actually run both Jest and Playwright in the same codebase at the same time
+summary: How to actually run both test runners in the same codebase at the same time
+isReleased: true
+isSequel: false
+lastModDate: 2023-09-01T09:15:00-0401
+firstModDate: 2023-09-01T09:15:00-0401
+minutesToRead: 18
+tags:
+ - 'jest'
+ - 'playwright'
+---
\ No newline at end of file
diff --git a/public/blogs/privacy-policy-template.mdx b/public/blogs/privacy-policy-template.mdx
deleted file mode 100644
index 64b3b245..00000000
--- a/public/blogs/privacy-policy-template.mdx
+++ /dev/null
@@ -1,94 +0,0 @@
----
-title: Privacy Policy
-seoTitle: Privacy policy BS template
-summary: Privacy prolicy templates
-isReleased: true
-isSequel: false
-firstModDate: 2020-04-20T09:15:00-0400
-lastModDate: 2023-04-20T09:15:00-0400
-minutesToRead: 3
-tags:
- - 'policies'
- - 'legal'
----
-
-### Code snippets testers
-
-```python
-import a from day
-from typing import Literal
-
-a = Literal['a','b','c']
-
-print(a.readme)
-```
-
-also
-
-```typescript
-interface Hey {
- data: string;
-}
-```
-
-# **Privacy Policy**
-
-
- ashgw ("we" or "us") is committed to protecting the privacy of our users. This
- Privacy Policy outlines how we collect, use, and safeguard your personal
- information. By using our services, you consent to the practices described in
- this policy. Our guiding principle is to collect only what we need. Here's
- what that means in practice.
-
-
-### **Your Information**
-
-
-
-When you sign up for our product or service, we may request certain identifying information, such as your name and email address. This allows us to personalize your new account.
-
-It's important to note that none of this information is stored on our database. Instead, for the purposes of managing your plan, subscription, or purchase, we securely hash and encrypt your email address, ensuring a high level of privacy and security.
-
-
-
-### **Authentication**
-
-
-
-As part of our authentication process, we exclusively employ OAuth2 with trusted providers like Google. This enables us to access your name and profile image session data stored securely in your browser. Please rest assured that these specific details are not permanently stored in our database infrastructure. They serve their purpose solely for the duration of your active session on our platform.
-
-
-
-### **Cookies**
-
-
-
-We do use persistent first-party cookies to store certain preferences, making it easier for you to use our applications. A cookie is a piece of text stored by your browser to help it remember your login information, site preferences, and more. You can adjust cookie retention settings in your own browser.
-
-
-
-### **User-Generated Requests**
-
-
-
-When you use our service to generate AI images based on a word or phrase, we collect the input provided. This information is used solely to generate the requested image and is not stored or associated with your personal information.
-
-
-
-### **Security**
-
-
-
-All data is encrypted via SSL/TLS when transmitted from our servers to your browser.
-
-
-
-### **Changes**
-
-
-
-We may update this policy as needed to comply with relevant regulations and reflect any new practices.
-
-Should you have any questions, comments, or concerns regarding this privacy policy, your data, or your rights in regard to your information, please don't hesitate to reach out. You can [contact](/contact) us and we'll be more than happy to assist you!
-
-
diff --git a/public/blogs/redis-instances-local-testing.mdx b/public/blogs/redis-instances-local-testing.mdx
new file mode 100644
index 00000000..b89532e5
--- /dev/null
+++ b/public/blogs/redis-instances-local-testing.mdx
@@ -0,0 +1,394 @@
+---
+title: Test Redis with Docker
+seoTitle: How to use Docker to to test Redis connections without resorting to mocks
+summary: A containerized approach for testing Redis connections instead resorting to mocks
+isReleased: true
+isSequel: false
+firstModDate: 2022-08-12T09:15:00-0400
+lastModDate: 2022-08-12T09:15:00-0400
+minutesToRead: 4
+tags:
+ - 'redis'
+ - 'docker'
+ - 'compose'
+---
+
+
+
Problem
+
+ So, you're using Redis to keep your API's rate in check , you're probably using cloud instances for prod and you're trying to
+ test your app logic, the natural inclination is to mock these connections and call it a day, don't! Mocking should be reserved for situations where absolute
+ necessity dictates or when replication of specific conditions proves unattainable. So here's a brief solution that should be language/Framework/Lib agnostic
+
+
Solution
+
+ I'll be using Python for this demo with FastAPI as a
+ framework and Poetry as the package manager,
+ but it doesn't matter, the core concept remains the same regardless of the stack being used.
+
+ pre-requisites:
+ - \- Python
+ - \- Docker & Compose
+
+
+ These are the basic endpoints that are rate-limited
+
+
+
+where if you curl any of these endpoints once a minute you should get
+
+Whereas if you curl any of these endpoints twice a minute you should get
+
+
+
+
+ For the rate limiting logic, I'll use ``fastapi_limiter``. Though you can
+ roll out your own.
+
+Here's a state of the art, robust, elegant and 120% prod ready service
+ raio.Redis:
+ return await raio.from_url(
+ url=f"redis://{RedisData.USERNAME}:{RedisData.PASSWORD}@localhost:{RedisData.PORT}",
+ encoding="utf-8",
+ decode_responses=True,
+ )
+
+
+@asynccontextmanager
+async def lifespan(_app: FastAPI) -> AsyncGenerator[None, None]:
+ await FastAPILimiter.init(await local_redis_connection()) # run when: app starts
+ yield
+ await FastAPILimiter.close() # run when: app shuts down
+
+
+async def limiter_dependency(req: Request, res: Response) -> None:
+ if req.url.path in RATE_LIMITED_PATHS:
+ await RateLimiter(times=2, minutes=1).__call__(req, res)
+
+
+api = FastAPI(
+ dependencies=[Depends(limiter_dependency)],
+ lifespan=lifespan,
+)
+
+
+for path in RATE_LIMITED_PATHS:
+ @api.get(path, tags=["rate_limited"])
+ def rate_limited() -> JSONResponse:
+ return JSONResponse({"detail":"you'll see me once a minute"})
+
+
+if __name__ == "__main__":
+ run(api, host="0.0.0.0", port=8000)
+`}
+ language="python"
+ showLineNumbers={false}
+/>
+The current project structure:
+
+
+here's the **`redis.conf`** file
+
+
+
+ This is the most basic config you can use for testing purposes. you can read
+ more about all the config options
+ here
+
+ To actually run it mfs need a Dockerfile:
+
+
+ /sys/kernel/mm/transparent_hugepage/enabled" > /etc/rc.local \
+
+&& chmod +x /etc/rc.local
+
+# resolve latency memory issues
+
+RUN echo "vm.overcommit_memory = 1" >> /etc/sysctl.conf \
+ && cat /etc/sysctl.conf
+
+CMD ["redis-server", "redis.conf"]
+`}
+language="docker"
+showLineNumbers={false}
+/>
+
+you can run this directly with Docker but I prefer to use **``docker-compose``** instead
+
+
+if your run compose now with
+
+
+
+ You'll have Redis running, but how do you coordinate with the app you're
+ trying to run? To ensure it only starts when Redis is up and running, one way
+ is to curl the Redis server. If the curl operation is successful, proceed to
+ run the app and conduct tests, though attempting to curl Redis will likely
+ result in receiving
+
+ GET / HTTP/1.1
+> Host: localhost:40185
+> User-Agent: curl/7.81.0
+> Accept: */*
+>
+* Received HTTP/0.9 when not allowed
+* Closing connection
+curl: (1) Received HTTP/0.9 when not allowed
+`}
+ language="bash"
+ showLineNumbers={false}
+/>
+
+ To work around this, you could either run your API with Compose as well.
+ However, for testing purposes, this might be totally unnecessary. Another
+ workaround is to have a service act as a trigger that you can curl. This
+ service depends on Redis, ensuring that it only runs if Redis is functioning
+ correctly. An example of such a service could be an **NGINX** server (~48MB image), that returns
+ a non null response upon curling. The modified
+ **`compose.yaml`** file is updated as follows:
+
+
+
+now if you run compose again:
+
+Use this **``test``** script to test your service
+/dev/null; do
+ sleep 1
+done
+python -m api &
+server_pid=$!
+##
+pytest # or any testing tool or scripts to use
+##
+kill $server_pid
+docker-compose down
+`}
+ language="bash"
+ showLineNumbers={false}
+/>
+
+ This script orchestrates the **Docker-Compose** configs, runs it in the background,
+ waits for the **NGINX** trigger
+ to be accessible, runs the **FastAPI** app, executes tests, shuts down the
+ server, and tears down the **Docker** containers.
+
+
+You can implement your own testing logic , using any test runner.
+
+Now since I'm using **FastAPI** I will omit the server running step from the test script
+, as **FastAPI** provides a **``TestClient``** class you can use to test your app logic
+without having to actually run the server. Also if you're using **``Pytest``** you can skip/ignore tests if a
+condition is not met, in this case, if no conatiners are spun up, skip. The idea might be like
+
+If you use **Go** for example an abstract setup might be like
+
+
+But the idea remains the same, scale redis container(s) before tests and scale down and clean up after, the only part changing in the script
+is the test runner, instead of Python's **``pyest``** it'll be **`go test`**, if you use rust then it's **`cargo test`** and so on...
\ No newline at end of file
diff --git a/public/blogs/simple.mdx b/public/blogs/simple.mdx
deleted file mode 100644
index 0d3e4b0a..00000000
--- a/public/blogs/simple.mdx
+++ /dev/null
@@ -1,87 +0,0 @@
----
-title: Simple
-seoTitle: Simple yapping nonetheless
-summary: Simple yapping nonetheless
-isReleased: true
-isSequel: false
-lastModDate: 2015-04-20T09:15:00-0400
-firstModDate: 2015-04-20T09:15:00-0400
-minutesToRead: 30
-tags:
- - 'journey'
- - 'career'
----
-
-
Server
-
- First you might want to yeet the **`Server`** & **`X-Powered-By`** headers (the latter being
- unofficial), preferably through the server configs, or check `no_srv.go`. I have metioned this actually here before
-
-> _Security through obscurity ainβt all that chief, but it's just a good complementary security measure._
-
-To test that you've removed this entirely you can use curl:
-
-
-
- If youd like to preserve the default values for a theme option but
- also add new values, add your extensions under the theme.extend key in
- your configuration file. Values under this key are merged with
- existing theme values and automatically become available as new
- classes that you can use. As an example, here we extend the fontFamily
- property to add the font-display class that can change the font used
- on an element: If youd like to preserve the default values for a theme
- option but also add new values, add your extensions under the
- theme.extend key in your configuration file. Values under this key are
- merged with existing theme values and automatically become available
- as new classes that you can use. As an example, here we extend the
- fontFamily property to add the font-display class that can change the
- font used on an element: If youd like to preserve the default values
- for a theme option but also add new values, add your extensions under
- the theme.extend key in your configuration file.
-
- Values under this key
- are merged with existing theme values and automatically become
- available as new classes that you can use. As an example, here we
- extend the fontFamily property to add the font-display class that can
- change the font used on an element: If youd like to preserve the
- default values for a theme option but also add new values, add your
- extensions under the theme.extend key in your configuration file.
- Values under this key are merged with existing theme values and
- automatically become available as new classes that you can use. As an
- example, here we extend the fontFamily property to add the
- font-display class that can change the font used on an element: If
- youd like to preserve the default values for a theme option but also
- add new values, add your extensions under the theme.extend key in your
- configuration file. Values under this key are merged with existing
- theme values and automatically become available as new classes that
- you can use. As an example, here we extend the fontFamily property to
- add the font-display class that can change the font used on an
- element: If youd like to preserve the default values for a theme
- option but also add new values, add your extensions under the
- theme.extend key in your configuration file. Values under this key are
- merged with existing theme values and automatically become available
- as new classes that you can use. As an example, here we extend the
- fontFamily property to add the font-display class that can change the
- font used on an element: If youd like to preserve the default values
- for a theme option but also add new values, add your extensions under
- the theme.extend key in your configuration file.
-
-
- Values under this key
- are merged with existing theme values and automatically become
- available as new classes that you can use. As an example, here we
- extend the fontFamily property to add the font-display class that can
- change the font used on an element: If youd like to preserve the
- default values for a theme option but also add new values, add your
- extensions under the theme.extend key in your configuration file.
- Values under this key are merged with existing theme values and
- automatically become available as new classes that you can use. As an
- example, here we extend the fontFamily property to add the
- font-display class that can change the font used on an element: If
- youd like to preserve the default values for a theme option but also
- add new values, add your extensions under the theme.extend key in your
- configuration file. Values under this key are merged with existing
- theme values and automatically become available as new classes that
- you can use. As an example, here we extend the fontFamily property to
- add the font-display class that can change the font used on an
-
diff --git a/public/blogs/tester.mdx b/public/blogs/tester.mdx
deleted file mode 100644
index d3307cbb..00000000
--- a/public/blogs/tester.mdx
+++ /dev/null
@@ -1,178 +0,0 @@
----
-title: Tester
-seoTitle: This is how to migrate from vercel to AWS
-summary: This is how to migrate from vercel to AWS
-isReleased: true
-isSequel: false
-lastModDate: 2024-02-20T09:15:00-0400
-firstModDate: 2024-02-20T09:15:00-0400
-minutesToRead: 13
-tags:
- - 'aws'
- - 'vercel'
- - 'serverless'
----
-
-
Privacy Policy
-
- First we might talk about how to run in parallel and run the app on any machine, you can choose from two methods:
-
-Using **``getStaticQueryParams()``** for isolation or, you can use Google if already have Python installed, the latter option.
-**During the installation process, you will receive instructions on how to re-run the app if needed, one can mention:**
-
-* \- **Referrer**: Static site generation
-
-
-- \- **Oppenheimer**: Beatle public asssessment
-
- {' '}
-
- {' '}
-
-
-
-- \- **Crunch**: Shuttle is new
-
-
-> > _NOTE: The installation may take some time as the dependencies are quite heavy._
-
-
-,
-}
-`}
-language="rust"
-showLineNumbers={true}
-
->
-
-
Your Information
-
- When you sign up for our product or service, we may request certain
- identifying information, such as your name and email address. This allows us
- to personalize your new account. It's important to note that none of this
- information is stored in our database. Instead, for the purposes of managing
- your plan, subscription, or purchase, we securely hash and encrypt your email
- address, ensuring a high level of privacy and security.
-
- None:
- with patch(
- "fastauth.providers.google.google.Google._request_access_token"
- ) as mock_token_request:
- mock_response = AsyncMock()
- mock_response.status_code = StatusCode.OK
- mock_response.json = valid_token_response
- mock_token_request.return_value = mock_response
- _result = await google._request_access_token(
- state=op.state,
- code_verifier=op.code_verifier,
- code="...",
- )
-`}
-language="python"
-showLineNumbers={true}
-
->
-
-
-
-
-
-
Authentication
-
- As part of our authentication process, we exclusively employ OAuth2 with trusted providers like Google. This enables us to access your name and profile image session data stored securely in your browser. Please rest assured that these specific details are not permanently stored in our database infrastructure. They serve their purpose solely for the duration of your active session on our platform.
-
-
Cookies
-
- We do use persistent first-party cookies to store certain preferences, making it easier for you to use our applications. A cookie is a piece of text stored by your browser to help it remember your login information, site preferences, and more. You can adjust cookie retention settings in your own browser.
-
-
User-Generated Requests
-
- When you use our service to generate AI images based on a word or phrase, we collect the input provided. This information is used solely to generate the requested image and is not stored or associated with your personal information.
-
-
Security
-
-Loading video...}>
-
-
- )
-}
-
-async function VideoComponent({ fileName }) {
- const { blobs } = await list({
- prefix: fileName,
- limit: 1,
- })
- const { url } = blobs[0]
-
- return (
-
- )
-}`}
- language="typescript"
- showLineNumbers={true}
- copy={false}
->
- {' '}
-
-
- All data is encrypted via SSL/TLS when transmitted from our servers to your
- browser.
-
-
-
Changes
-
- We may update this policy as needed to comply with relevant regulations and reflect any new practices.
- Should you have any questions, comments, or concerns regarding this privacy policy, your data, or your rights in regard to your information, please don't hesitate to reach out. You can contact us and we'll be more than happy to assist you!
-
diff --git a/src/app/(pages)/x/page.tsx b/src/app/(pages)/x/page.tsx
index 73cb30c1..e587a6bc 100644
--- a/src/app/(pages)/x/page.tsx
+++ b/src/app/(pages)/x/page.tsx
@@ -1,10 +1,2 @@
-import React from 'react';
-
-export default function SplitCard() {
- return (
- <>
- Lorem ipsum dolor, sit amet consectetur adipisicing elit. Amet hic
- voluptatum hic omnis laudantium accusamus.
- >
- );
-}
+import LoadingScreen from '../blog/loading';
+export default LoadingScreen;
diff --git a/src/app/components/__futures__/light-grid.tsx b/src/app/components/__futures__/light-grid.tsx
index c877b10f..596db491 100644
--- a/src/app/components/__futures__/light-grid.tsx
+++ b/src/app/components/__futures__/light-grid.tsx
@@ -1,15 +1,39 @@
-export default function LightGrid() {
+'use client';
+import gsap from 'gsap';
+import { useGSAP } from '@gsap/react';
+import { useRef } from 'react';
+
+const LightGrid: React.FC = () => {
+ const ref = useRef(null);
+ useGSAP(
+ () => {
+ const tl = gsap.timeline();
+ tl.to('dxd', {
+ duration: 1,
+ scale: 0.1,
+ y: 40,
+ ease: 'power1.inOut',
+ stagger: {
+ grid: [10, 10],
+ from: 'center',
+ amount: 1.5,
+ },
+ });
+ },
+ { scope: ref }
+ );
+
return (
<>