Skip to content

Commit

Permalink
Add technical logs section, add individual technical log
Browse files Browse the repository at this point in the history
  • Loading branch information
saulprl-enc committed Jul 29, 2024
1 parent bbf47c7 commit 3a5c338
Show file tree
Hide file tree
Showing 12 changed files with 243 additions and 7 deletions.
4 changes: 2 additions & 2 deletions src/components/hero/hero.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ export const Hero = () => {
<LinkButton to="/blog" className="bg-encora-red">
Blog
</LinkButton>
<LinkButton to="/certifications" className="bg-encora-green">
Certifications
<LinkButton to="/technical-logs" className="bg-encora-blue">
Technical Logs
</LinkButton>
</div>
</div>
Expand Down
4 changes: 2 additions & 2 deletions src/components/navbar/navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ export const Navbar: FC<NavigationMenuProps> = ({
</CustomNavLink>
</NavigationMenuItem>
<NavigationMenuItem>
<CustomNavLink to="/certifications">
<NavigationMenuLink>Certifications</NavigationMenuLink>
<CustomNavLink to="/technical-logs">
<NavigationMenuLink>Technical Logs</NavigationMenuLink>
</CustomNavLink>
</NavigationMenuItem>
</NavigationMenuList>
Expand Down
48 changes: 48 additions & 0 deletions src/components/technical-logs/technical-log-item.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { FC, ReactNode } from "react";
import { Link, LinkProps } from "react-router-dom";

import { cn } from "@/lib/utils";
import { format } from "date-fns";

export const TechnicalLogItem: FC<LinkProps> = ({ className, ...props }) => {
return (
<Link
className={cn(
"group relative flex flex-col w-full min-h-24 overflow-hidden p-2 pb-4 rounded-md bg-encora-blue/10 border-2 border-encora-blue transition-all hover:scale-105 hover:bg-encora-blue/15 focus:scale-95 md:w-1/3",
className
)}
{...props}
/>
);
};

interface TitleProps {
className?: string;
children: ReactNode;
}

export const TechnicalLogTitle: FC<TitleProps> = ({ className, children }) => {
return (
<h3 className={cn("font-bold line-clamp-2 text-xl", className)}>
{children}
</h3>
);
};

interface DateProps {
date: Date;
className?: string;
}

export const TechnicalLogDate: FC<DateProps> = ({ className, date }) => {
return (
<span
className={cn(
"absolute bottom-1 right-0 w-1/2 text-center bg-encora-blue text-white text-base transition-all",
className
)}
>
{format(date, "PP")}
</span>
);
};
42 changes: 42 additions & 0 deletions src/components/technical-logs/technical-logs-list.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { cva, VariantProps } from "class-variance-authority";
import { FC } from "react";
import { cn } from "@/lib/utils";
import { technicalLogs } from "./tecnical-logs";
import {
TechnicalLogDate,
TechnicalLogItem,
TechnicalLogTitle,
} from "./technical-log-item";

const variants = cva(["w-full gap-2"], {
variants: {
container: {
fullPage: "grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3",
section: "flex items-stretch",
},
},
defaultVariants: {
container: "section",
},
});

interface Props {
variant?: VariantProps<typeof variants>["container"];
}

export const TechnicalLogsList: FC<Props> = ({ variant = "section" }) => {
return (
<div className={cn(variants({ container: variant }))}>
{technicalLogs.map((log) => (
<TechnicalLogItem
key={log.id}
to={`/technical-logs/${log.slug}`}
className={cn(variant === "fullPage" && "md:w-full")}
>
<TechnicalLogTitle>{log.title}</TechnicalLogTitle>
<TechnicalLogDate date={new Date(log.date)} />
</TechnicalLogItem>
))}
</div>
);
};
23 changes: 23 additions & 0 deletions src/components/technical-logs/technical-logs-section.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { LinkButton } from "../button/link-button";
import { Section } from "../section/section";
import { TechnicalLogsList } from "./technical-logs-list";
import { technicalLogs } from "./tecnical-logs";

export const TechnicalLogsSection = () => {
return (
<Section>
<div className="w-full flex flex-col gap-6 border-2 border-encora-blue rounded-md p-2">
<h2 className="text-3xl font-bold text-encora-blue">Technical Logs</h2>
<p>This section will contain all of my technical logs.</p>
<TechnicalLogsList variant="section" />
{technicalLogs.length > 3 && (
<div className="w-full flex items-center justify-center">
<LinkButton to="/blog" className="bg-encora-red">
See more
</LinkButton>
</div>
)}
</div>
</Section>
);
};
22 changes: 22 additions & 0 deletions src/components/technical-logs/tecnical-logs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { ReactNode } from "react";

import { mdxComponents } from "@/mdx/components/components";
import Permutations from "@/mdx/technical-logs/permutations.mdx";

export type TTechnicalLog = {
id: number;
title: string;
date: string;
slug: string;
content: ReactNode;
};

export const technicalLogs: Array<TTechnicalLog> = [
{
id: 1,
title: "Permutations",
date: "2024-07-28",
slug: "permutations",
content: <Permutations components={{ ...mdxComponents }} />,
},
];
19 changes: 17 additions & 2 deletions src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,13 @@ import { createHashRouter, RouterProvider } from "react-router-dom";
import { Root } from "./routes/root.tsx";
import { HomePage } from "./routes/index.tsx";
import { BlogPage } from "./routes/blog.tsx";
import { BlogEntry, loader as entryLoader } from "./routes/blog-entry.tsx";
import { BlogEntry, blogEntryLoader } from "./routes/blog-entry.tsx";
import { NotFound } from "./routes/not-found.tsx";
import { TechnicalLogsPage } from "./routes/technical-logs.tsx";
import {
TechnicalLogEntry,
technicalLogLoader,
} from "./routes/technical-log-entry.tsx";

const router = createHashRouter([
{
Expand All @@ -15,7 +20,17 @@ const router = createHashRouter([
children: [
{ path: "/", element: <HomePage /> },
{ path: "/blog", element: <BlogPage /> },
{ path: "/blog/:entrySlug", element: <BlogEntry />, loader: entryLoader },
{
path: "/blog/:entrySlug",
element: <BlogEntry />,
loader: blogEntryLoader,
},
{ path: "/technical-logs", element: <TechnicalLogsPage /> },
{
path: "/technical-logs/:logSlug",
element: <TechnicalLogEntry />,
loader: technicalLogLoader,
},
{ path: "*", element: <NotFound /> },
],
},
Expand Down
40 changes: 40 additions & 0 deletions src/mdx/technical-logs/permutations.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
export { Layout as default } from "../components/components.tsx";

# Permutations

<br />
## Overview

<br />
_Permutations_ consists of generating all of the possible permutations (modifying
the order of the elements without affecting its structure) for an array of numbers.
In this case, we receive an array of numbers and should output a list of number arrays,
where every array is a permutation.

<br />
## Context

<br />
In order to solve this problem, you should have a good understanding of [permutations](https://en.wikipedia.org/wiki/Permutation),
[array iteration](https://www.w3schools.com/js/js_array_iteration.asp), and [recursion](https://www.freecodecamp.org/news/recursion-in-javascript/).

<br />
## Solution

<br />
For this solution, I decided to implement a recursive function since I had worked
on something similar regarding combinations. In this case, though, I needed to generate
permutations. Like every recursive function, we must start with a base case so we
don't end up blowing up our computer. Since we will be internally modifying the array,
our base case will be to return an array with a single value when the array is of
length 1. Afterwards, we will loop through the array to extract the first number
of the array and then permute the remaining elements. After recursion is done, we
add all of the permutations obtained and store them in another array.

<br />
## Alternative solutions

<br />
Since I had previously worked on a similar function for combinations, I went directly
with the aforementioned approach, recursion. However, if it's possible with recursion,
it's also possible with loops.
2 changes: 1 addition & 1 deletion src/routes/blog-entry.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useLoaderData } from "react-router-dom";

import { blogEntries, TBlogEntry } from "@/components/blog/entries";

export function loader({ params }) {
export function blogEntryLoader({ params }) {
if (!params || !params.entrySlug) {
throw new Error("Received unexpected params");
}
Expand Down
2 changes: 2 additions & 0 deletions src/routes/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { BlogSection } from "@/components/blog/blog-section";
import { Hero } from "@/components/hero/hero";
import { TechnicalLogsSection } from "@/components/technical-logs/technical-logs-section";

export const HomePage = () => {
return (
<>
<Hero />
<BlogSection />
<TechnicalLogsSection />
</>
);
};
30 changes: 30 additions & 0 deletions src/routes/technical-log-entry.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { useLoaderData } from "react-router-dom";

import {
technicalLogs,
TTechnicalLog,
} from "@/components/technical-logs/tecnical-logs";

export function technicalLogLoader({ params }) {
if (!params || !params.logSlug) {
throw new Error("Received unexpected params");
}

const entry = technicalLogs.find((entry) => entry.slug === params.logSlug);

if (!entry) {
throw new Error("Couldn't find the specified resource");
}

return entry;
}

export const TechnicalLogEntry = () => {
const data = useLoaderData() as TTechnicalLog;

return (
<div className="w-full flex items-start justify-start pt-2 pb-32 px-2">
{data.content}
</div>
);
};
14 changes: 14 additions & 0 deletions src/routes/technical-logs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Section } from "@/components/section/section";
import { TechnicalLogsList } from "@/components/technical-logs/technical-logs-list";

export const TechnicalLogsPage = () => {
return (
<Section>
<div className="w-full flex flex-col gap-6 border-2 border-encora-blue rounded-md p-2">
<h2 className="text-3xl font-bold text-encora-blue">Technical Logs</h2>
<p>This section will contain all of my technical logs.</p>
<TechnicalLogsList variant="fullPage" />
</div>
</Section>
);
};

0 comments on commit 3a5c338

Please sign in to comment.