Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions components.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": false,
"tsx": true,
"tailwind": {
"config": "tailwind.config.js",
"css": "styles/global.scss",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
},
"iconLibrary": "lucide"
}
144 changes: 80 additions & 64 deletions components/card/card.tsx
Original file line number Diff line number Diff line change
@@ -1,76 +1,92 @@
"use client";

import Link from "next/link";
import Image from "next/image";
import { Text, Title, Box } from "@mantine/core";
import Badge from "../tailwind/badge";
import Button from "../tailwind/button";
import { motion } from "framer-motion";
import {
Card as UICard,
CardContent,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";

interface CardProps {
thumbnail: string;
title: string;
shortDescription: string;
tags: string;
link: string;
thumbnail: string;
title: string;
shortDescription: string;
tags: string;
link: string;
}

const Card = ({
thumbnail, title, shortDescription, tags, link,
}: CardProps) => {
let tagsArray: string[] = [];
if (tags) {
tagsArray = Array.isArray(tags) ? tags : tags.split(",").map(tag => tag.trim());
}

const getLink = (link: string) => {
if (link.startsWith("http")) {
return link;
} else {
return `/blog/${link}`;
}
};
thumbnail,
title,
shortDescription,
tags,
link,
}: CardProps) => {
const tagsArray: string[] = tags
? Array.isArray(tags)
? (tags as unknown as string[])
: (tags as string).split(",").map((tag) => (tag as string).trim())
: [];

const heightWithThumbnail = "430px";
const heightWithoutThumbnail = "280px";
const getLink = (href: string) =>
href.startsWith("http") ? href : `/blog/${href}`;

return (
<Box
className="flex flex-col shadow-md border-0 m-2 p-4 bg-neutral-100 rounded-md dark:bg-neutralGray-700 dark:text-white dark:shadow-gray-900"
style={{ height: thumbnail ? heightWithThumbnail : heightWithoutThumbnail }}
>
<Box style={{ flexGrow: 1, display: "flex", flexDirection: "column" }}>
{thumbnail && (
<div className="mb-4">
<Image
src={thumbnail}
alt={`Blog ${title} Description`}
width={0}
height={0}
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
className="w-full h-48 rounded-md object-cover"
/>
</div>
)}
<Box style={{ flexGrow: 1, display: "flex", flexDirection: "column", justifyContent: "space-between" /* minHeight removed as parent has fixed height now */ }}>
<div>
<Title order={6} className="text-primary uppercase" mb="xs">{title}</Title>
<Text size="sm" lineClamp={3} mb="sm">{shortDescription}</Text>
<div>
{
tagsArray.length ?
tagsArray.map(
(tag) => <Badge text={tag} className="mr-2 dark:bg-dark-primary-300" key={tag}/>,
)
: ""}
</div>
</div>
<Button variant="filled" fullWidth>
<Link href={getLink(link)} target="_blank">
Read more
</Link>
</Button>
</Box>
</Box>
</Box>
);
return (
<motion.div
initial={{ opacity: 0, y: 16 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: "-20px" }}
transition={{ duration: 0.3 }}
whileHover={{ y: -4, transition: { duration: 0.2 } }}
className="h-full"
>
<UICard className="flex h-full flex-col transition-shadow hover:shadow-none hover:translate-x-boxShadowX hover:translate-y-boxShadowY">
{thumbnail ? (
<div className="relative h-48 w-full overflow-hidden rounded-t-base">
<Image
src={thumbnail}
alt={`${title} thumbnail`}
fill
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
className="object-cover"
/>
</div>
) : null}
<CardHeader className="flex-1">
<CardTitle className="line-clamp-2 text-base uppercase tracking-wide">
{title}
</CardTitle>
</CardHeader>
<CardContent className="flex-1 space-y-2 pt-0">
<p className="line-clamp-3 text-sm text-foreground">
{shortDescription}
</p>
{tagsArray.length > 0 && (
<div className="flex flex-wrap gap-1">
{tagsArray.map((tag) => (
<Badge key={tag} variant="neutral" className="text-xs">
{tag}
</Badge>
))}
</div>
)}
</CardContent>
<CardFooter className="pt-0">
<Button variant="default" size="default" className="w-full" asChild>
<Link href={getLink(link)} target="_blank" className="no-underline">
Read more
</Link>
</Button>
</CardFooter>
</UICard>
</motion.div>
);
};

export default Card;
150 changes: 82 additions & 68 deletions components/header/header.tsx
Original file line number Diff line number Diff line change
@@ -1,78 +1,92 @@
"use client";

import Link from "next/link";
import Image from "next/image";
import React, { useState } from "react";
import { Burger, Box, Paper } from "@mantine/core";
import Button from "../tailwind/button";
import React from "react";
import { Menu } from "lucide-react";
import { Button } from "@/components/ui/button";
import {
Sheet,
SheetContent,
SheetHeader,
SheetTitle,
SheetTrigger,
} from "@/components/ui/sheet";

export interface HeaderProps {
logoUrl: string;
navMap?: Array<{ href: string, label: string }>;
logoUrl: string;
navMap?: Array<{ href: string; label: string }>;
}

export const Header: React.FC<HeaderProps> = ({logoUrl, navMap = []}) => {
const [opened, setOpened] = useState(false);
const title = opened ? "Close navigation" : "Open navigation";

const getHref = (href: string) => {
if (href.startsWith("/")) {
return href;
}
return `/${href}`;
};
export const Header: React.FC<HeaderProps> = ({ logoUrl, navMap = [] }) => {
const getHref = (href: string) => {
if (href.startsWith("/")) return href;
return `/${href}`;
};

return (
<Box component="header" className="bg-brandMutedYellow-600 py-4 md:py-8 relative">
<Box className="container flex justify-between items-center">
<Link href="/">
<Image height={56} width={250} src={logoUrl} alt="Logo" priority />
</Link>
const navLinks = (
<>
{navMap.length > 0 &&
navMap.map((item) => (
<Button key={item.href} variant="neutral" size="default" asChild>
<Link href={getHref(item.href)} className="no-underline">
{item.label}
</Link>
</Button>
))}
</>
);

<Box className="hidden md:flex md:items-center space-x-2">
{navMap.length > 0 && navMap.map((item) => (
<Button variant="filled" key={item.href}>
<Link href={getHref(item.href)} passHref legacyBehavior>
<a className="text-white no-underline hover:text-gray-200 px-3 py-2 rounded-md text-sm font-bold">
{item.label}
</a>
</Link>
</Button>
))}
</Box>
return (
<header className="sticky top-0 z-40 w-full border-b-2 border-border bg-main py-4 shadow-shadow md:py-6">
<div className="container flex justify-between items-center">
<Link href="/" className="flex-shrink-0">
<Image
height={56}
width={250}
src={logoUrl}
alt="Logo"
priority
className="h-10 w-auto md:h-14"
/>
</Link>

<Box className="md:hidden ml-4">
<Burger
opened={opened}
onClick={() => setOpened((o) => !o)}
title={title}
color="white"
/>
</Box>
</Box>
<nav className="hidden md:flex md:items-center gap-2">{navLinks}</nav>

{opened && (
<Paper
className="md:hidden absolute top-full left-0 right-0 z-20 shadow-lg"
bg="brandMutedYellow.6"
p="md"
withBorder
radius={0}
>
<ul className="flex flex-col space-y-2">
{navMap.length > 0 && navMap.map((item) => (
<li key={item.href}>
<Link href={item.href} passHref legacyBehavior>
<a
className="block text-white no-underline hover:text-gray-200 px-3 py-2 rounded-md text-base font-medium"
onClick={() => setOpened(false)}
>
{item.label}
</a>
</Link>
</li>
))}
</ul>
</Paper>
)}
</Box>
);
};
<div className="flex md:hidden">
<Sheet>
<SheetTrigger
asChild
aria-label="Open navigation menu"
className="min-h-[44px] min-w-[44px] rounded-base border-2 border-border bg-main-foreground p-2.5 text-main shadow-shadow hover:translate-x-boxShadowX hover:translate-y-boxShadowY hover:shadow-none"
>
<button type="button">
<Menu className="size-6" />
</button>
</SheetTrigger>
<SheetContent side="right" className="w-[min(100vw-2rem,320px)]">
<SheetHeader>
<SheetTitle className="text-left">Menu</SheetTitle>
</SheetHeader>
<ul className="mt-6 flex flex-col gap-2">
{navMap.length > 0 &&
navMap.map((item) => (
<li key={item.href}>
<Button
variant="neutral"
size="default"
className="w-full justify-start text-left"
asChild
>
<Link href={getHref(item.href)}>{item.label}</Link>
</Button>
</li>
))}
</ul>
</SheetContent>
</Sheet>
</div>
</div>
</header>
);
};
Loading
Loading