Compare commits

..

10 Commits

Author SHA1 Message Date
Craig
2a701d0291 Refactor components for improved readability: standardize import order, enhance formatting, and ensure consistent newline usage across ColorPalette, Contact, FeatureCards, FooterSocial, HeaderSimple, HeroTitle, and Home.page components. 2025-04-16 12:17:38 +01:00
Craig
913c40b9ec Add FooterSocial component: implement social media links with responsive styling for enhanced footer experience. 2025-04-16 12:14:17 +01:00
Craig
e06ec3d5df Update index.html: change favicon to a new PNG image and update the page title to 'Craig Macfadyen'. Add dark mode icon asset. 2025-04-16 11:59:27 +01:00
Craig
42174ac9f7 Update HeaderSimple component: replace MantineLogo with a custom Text element displaying the name 'Craig Macfadyen' for a personalized header experience. 2025-04-16 11:58:06 +01:00
Craig
30fbe7be35 Add new feature card to FeatureCards component: introduce 'Cutting-Edge Research' card with an icon and description to highlight ongoing advancements in AI research. 2025-04-16 11:22:31 +01:00
Craig
44aa84a127 Add new features to FeatureCards component: include 'Privacy Focused' and 'Open Source' cards with corresponding icons and descriptions to enhance the showcase of expertise. 2025-04-16 11:04:40 +01:00
Craig
c3375f6cfd Update HeroTitle component: change job title from Data Scientist to Machine Learning Engineer to better reflect expertise and align with current industry terminology. 2025-04-16 10:54:59 +01:00
Craig
70228b655f Update FeatureCards component descriptions: enhance the text for computer vision and natural language processing to better convey expertise and business value. 2025-04-16 10:54:25 +01:00
Craig
3899e37f1e Update FeatureCards component icons: replace existing icons with new ones for improved visual representation of skills in computer vision, natural language processing, and data science. 2025-04-16 10:50:05 +01:00
Craig
7ef669f852 Remove ExpertiseSection component and styles; add FeatureCards component and associated styles to enhance the homepage with a new expertise showcase. 2025-04-16 10:49:25 +01:00
13 changed files with 219 additions and 94 deletions

View File

@@ -2,12 +2,12 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/src/favicon.svg" />
<link rel="icon" type="image/png" href="/src/assets/darkmode-small.png" />
<meta
name="viewport"
content="minimum-scale=1, initial-scale=1, width=device-width, user-scalable=no"
/>
<title>Vite + Mantine App</title>
<title>Craig Macfadyen</title>
</head>
<body>
<div id="root"></div>

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -13,4 +13,4 @@ const meta = {
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {};
export const Default: Story = {};

View File

@@ -1,4 +1,4 @@
import { Anchor, Container, Text, Stack } from '@mantine/core';
import { Anchor, Container, Stack, Text } from '@mantine/core';
import classes from './Contact.module.css';
export function Contact() {
@@ -25,7 +25,11 @@ export function Contact() {
</Text>
<Text size="lg">
LinkedIn:{' '}
<Anchor href="https://www.linkedin.com/in/craig-macfadyen-9a2041197" target="_blank" className={classes.link}>
<Anchor
href="https://www.linkedin.com/in/craig-macfadyen-9a2041197"
target="_blank"
className={classes.link}
>
linkedin.com/in/craigmacfadyen
</Anchor>
</Text>

View File

@@ -1,3 +0,0 @@
.section {
margin-top: 80px;
}

View File

@@ -1,61 +0,0 @@
import React from 'react';
import { Carousel } from '@mantine/carousel';
import { Container, Grid, Image, Stack, Text, Title } from '@mantine/core';
import classes from './ExpertiseSection.module.css';
interface ExpertiseSectionProps {
title: string;
content: string;
images: { url: string; alt: string }[];
viewMoreLink: string;
imageOnLeft?: boolean;
}
const ExpertiseSection: React.FC<ExpertiseSectionProps> = ({
title,
content,
images,
viewMoreLink: _viewMoreLink,
imageOnLeft = false,
}) => {
const slides = images.map((image) => (
<Carousel.Slide key={image.url}>
<Image
src={image.url}
alt={image.alt}
style={{ width: '100%', height: 'auto', objectFit: 'cover' }}
/>
</Carousel.Slide>
));
return (
<Container>
<Grid className={classes.section}>
<Grid.Col order={imageOnLeft ? 2 : 1} span={{ xs: 6, md: 8 }}>
<Stack>
<Title>{title}</Title>
<Text size="lg">{content}</Text>
{/* <Button component="a" href={viewMoreLink}>
View More
</Button> */}
</Stack>
</Grid.Col>
<Grid.Col order={imageOnLeft ? 1 : 2} span={{ xs: 6, md: 4 }}>
<Carousel
slideSize={300}
align="start"
slideGap="md"
controlsOffset="xl"
controlSize={28}
loop
withIndicators
>
{slides}
</Carousel>
</Grid.Col>
</Grid>
</Container>
);
};
export default ExpertiseSection;

View File

@@ -0,0 +1,39 @@
.title {
font-size: 34px;
font-weight: 900;
@media (max-width: $mantine-breakpoint-sm) {
font-size: 24px;
}
}
.description {
max-width: 600px;
margin: auto;
&::after {
content: '';
display: block;
background-color: var(--mantine-color-blue-filled);
width: 45px;
height: 2px;
margin-top: var(--mantine-spacing-sm);
margin-left: auto;
margin-right: auto;
}
}
.card {
border: 1px solid light-dark(var(--mantine-color-gray-1), var(--mantine-color-dark-5));
}
.cardTitle {
&::after {
content: '';
display: block;
background-color: var(--mantine-color-blue-filled);
width: 45px;
height: 2px;
margin-top: var(--mantine-spacing-sm);
}
}

View File

@@ -0,0 +1,90 @@
import { FaChartLine, FaCode, FaEye, FaLightbulb, FaMessage, FaShield } from 'react-icons/fa6';
import {
Badge,
Card,
Container,
Group,
SimpleGrid,
Text,
Title,
useMantineTheme,
} from '@mantine/core';
import classes from './FeatureCards.module.css';
const mockdata = [
{
title: 'Computer Vision',
description:
'I have experience in building computer vision models for a range of applications, from object detection to image segmentation. If your business works with images, these models can improve your efficiency and accuracy.',
icon: FaEye,
},
{
title: 'Natural Language Processing',
description:
'Expertise working with LLMs, from training to deployment. These state-of-the-art models are a powerful tool for a range of applications, and can drive your business forward.',
icon: FaMessage,
},
{
title: 'Data Science',
description:
'Sometimes you just need a simple model and some nice graphs. I can help you understand your data and build a model that works for you.',
icon: FaChartLine,
},
{
title: 'Privacy Focused',
description:
'Your data is valuable and sensitive. All my solutions are built with privacy and security in mind from the ground up, ensuring regulatory compliance and protecting your competitive advantage.',
icon: FaShield,
},
{
title: 'Open Source',
description:
'Leverage the power and innovation of open source technologies while avoiding vendor lock-in. This approach provides transparency, cost-effectiveness, and ensures your solutions remain maintainable long-term.',
icon: FaCode,
},
{
title: 'Cutting-Edge Research',
description:
'I stay continuously updated with the latest advancements in AI research and immediately apply emerging techniques to solve business problems. Your solutions will never be outdated or obsolete.',
icon: FaLightbulb,
},
];
export function FeaturesCards() {
const theme = useMantineTheme();
const features = mockdata.map((feature) => (
<Card key={feature.title} shadow="md" radius="md" className={classes.card} padding="xl">
<feature.icon size={50} color={theme.colors.blue[6]} />
<Text fz="lg" fw={500} className={classes.cardTitle} mt="md">
{feature.title}
</Text>
<Text fz="sm" c="dimmed" mt="sm">
{feature.description}
</Text>
</Card>
));
return (
<Container size="lg" py="xl">
<Group justify="center">
<Badge variant="filled" size="lg">
My Expertise
</Badge>
</Group>
<Title order={2} className={classes.title} ta="center" mt="sm">
What can I bring to your business?
</Title>
<Text c="dimmed" className={classes.description} ta="center" mt="md">
I've worked with a range of businesses, from startups to established companies, and I've
learned a lot about what works and what doesn't. I work across the full Machine Learning
stack, from data collection to model deployment.
</Text>
<SimpleGrid cols={{ base: 1, md: 3 }} spacing="xl" mt="50px">
{features}
</SimpleGrid>
</Container>
);
}

View File

@@ -0,0 +1,22 @@
.footer {
margin-top: 120px;
border-top: 1px solid light-dark(var(--mantine-color-gray-2), var(--mantine-color-dark-5));
}
.inner {
display: flex;
justify-content: space-between;
align-items: center;
padding-top: var(--mantine-spacing-xl);
padding-bottom: var(--mantine-spacing-xl);
@media (max-width: $mantine-breakpoint-xs) {
flex-direction: column;
}
}
.links {
@media (max-width: $mantine-breakpoint-xs) {
margin-top: var(--mantine-spacing-md);
}
}

View File

@@ -0,0 +1,46 @@
import { FaGithub, FaLinkedin } from 'react-icons/fa';
import { SiGitea } from 'react-icons/si';
import { ActionIcon, Container, Group, Text } from '@mantine/core';
import classes from './FooterSocial.module.css';
export function FooterSocial() {
return (
<div className={classes.footer}>
<Container className={classes.inner}>
<Text>Craig Macfadyen</Text>
<Group gap={0} className={classes.links} justify="flex-end" wrap="nowrap">
<ActionIcon
component="a"
target="_blank"
href="https://github.com/cdmacfadyen"
size="lg"
color="gray"
variant="subtle"
>
<FaGithub size={18} />
</ActionIcon>
<ActionIcon
component="a"
target="_blank"
href="https://gitea.craigmacfadyen.co.uk"
size="lg"
color="gray"
variant="subtle"
>
<SiGitea size={18} />
</ActionIcon>
<ActionIcon
component="a"
target="_blank"
href="https://www.linkedin.com/in/craig-macfadyen-9a2041197/"
size="lg"
color="gray"
variant="subtle"
>
<FaLinkedin size={18} />
</ActionIcon>
</Group>
</Container>
</div>
);
}

View File

@@ -1,6 +1,5 @@
import { Anchor, Burger, Container, Group } from '@mantine/core';
import { Burger, Container, Group, Text } from '@mantine/core';
import { useDisclosure } from '@mantine/hooks';
import { MantineLogo } from '@mantinex/mantine-logo';
import { ColorSchemeToggle } from '../ColorSchemeToggle/ColorSchemeToggle';
import classes from './HeaderSimple.module.css';
@@ -10,14 +9,16 @@ export function HeaderSimple() {
return (
<header className={classes.header}>
<Container size="md" className={classes.inner}>
<MantineLogo size={28} />
<Text fw={700} size="lg" style={{ userSelect: 'none', cursor: 'default' }}>
Craig Macfadyen
</Text>
<Group gap={5} visibleFrom="xs">
<Anchor href="#" className={classes.link}>
{/* <Anchor href="#" className={classes.link}>
CV
</Anchor>
<Anchor href="#" className={classes.link}>
Blog
</Anchor>
</Anchor> */}
</Group>
<Burger opened={opened} onClick={toggle} hiddenFrom="xs" size="sm" />

View File

@@ -14,9 +14,9 @@ export function HeroTitle() {
</h1>
<Text className={classes.description} c="dimmed">
Data Scientist with experience in consulting and research. Expertise in Computer Vision
and Large Language Models. Take a look at what I can do for your business and get in touch
if you have any questions or you'd like to work together!
Machine Learning Engineer with experience in consulting and research. Expertise in
Computer Vision and Large Language Models. Take a look at what I can do for your business
and get in touch if you have any questions or you'd like to work together!
</Text>
</Container>
</div>

View File

@@ -1,8 +1,7 @@
import { Container } from '@mantine/core';
import openWebUIGif from '@/assets/open-webui.gif';
import outputGif from '@/assets/output.gif';
import { Contact } from '@/components/ContactUs/Contact';
import ExpertiseSection from '@/components/ExpertiseSection/ExpertiseSection';
import { FeaturesCards } from '@/components/FeatureCards/FeatureCards';
import { FooterSocial } from '@/components/FooterSocial/FooterSocial';
import { HeaderSimple } from '@/components/HeaderSimple/HeaderSimple';
import { HeroTitle } from '@/components/HeroTitle/HeroTitle';
import Testimonial from '@/components/Testimonial/Testimonial';
@@ -12,24 +11,12 @@ export function HomePage() {
<>
<HeaderSimple />
<HeroTitle />
<ExpertiseSection
title="Computer Vision"
content="Expertise in developing and deploying computer vision models for various applications, including object detection, image classification, and more. Ask me about state-of-the-art real-time models for your business."
images={[{ url: outputGif, alt: 'Video Segmentation with SAM2.' }]}
viewMoreLink="/computer-vision"
imageOnLeft
/>
<ExpertiseSection
title="Natural Language Processing"
content="Building NLP models for tasks such as sentiment analysis, text classification, and language generation. If you need a chatbot for your business and care about privacy, or a simple text classification algorithm to understand your data, I can help."
images={[{ url: openWebUIGif, alt: 'Locally hosted LLM using oLLama and OpenWebUI.' }]}
viewMoreLink="/nlp"
imageOnLeft={false}
/>
<FeaturesCards />
<Container mt={20}>
<Testimonial />
</Container>
<Contact />
<FooterSocial />
</>
);
}