Compare commits

...

7 Commits

20 changed files with 3343 additions and 234 deletions

View File

@@ -0,0 +1,11 @@
---
description:
globs:
alwaysApply: true
---
Rule Name: development_workflow.mdc
Description:
- Do not move on to the next step of a task until user has confirmed the previous stage is finished. Pause occasionally and ask the user to accept changes.
- Run tests after changing code functionality.
- Use TDD principles where applicable.
- Before implementing code, consider if it is worth refactoring any code in the working area to be more clean, modular, and readable.

View File

@@ -23,6 +23,21 @@
{
"ignorePseudoClasses": ["global"]
}
]
],
"color-named": "never",
"color-no-hex": true,
"function-disallowed-list": [
"rgb",
"rgba",
"hsl",
"hsla"
],
"declaration-property-value-disallowed-list": {
"color": ["/^#/", "/^rgb/", "/^hsl/"],
"background-color": ["/^#/", "/^rgb/", "/^hsl/"],
"border-color": ["/^#/", "/^rgb/", "/^hsl/"],
"fill": ["/^#/", "/^rgb/", "/^hsl/"],
"stroke": ["/^#/", "/^rgb/", "/^hsl/"]
}
}
}

View File

@@ -1,5 +1,7 @@
# Mantine Vite template
The project is a well-structured, modern React application with a clean design and strong technical foundation. It effectively showcases Craig Macfadyen's professional expertise but would benefit from completing the missing features and addressing the navigation structure. The use of Mantine provides a solid UI foundation, and the component architecture supports maintainability and future expansion.
## Features
This template comes with the following features:

View File

@@ -0,0 +1,78 @@
# Current Color Usage Inventory
## Mantine Color Variables Used
### Basic Colors
- White: `var(--mantine-color-white)`
- Black: `var(--mantine-color-black)`
- Body: `var(--mantine-color-body)`
### Blue Shades
- Blue-0: `var(--mantine-color-blue-0)`
- Blue-1: `var(--mantine-color-blue-1)`
- Blue-4: `var(--mantine-color-blue-4)`
- Blue-6: `var(--mantine-color-blue-6)`
- Blue-7: `var(--mantine-color-blue-7)`
- Blue-filled: `var(--mantine-color-blue-filled)`
### Gray Shades
- Gray-0: `var(--mantine-color-gray-0)`
- Gray-3: `var(--mantine-color-gray-3)`
- Gray-4: `var(--mantine-color-gray-4)`
- Gray-5: `var(--mantine-color-gray-5)`
- Gray-7: `var(--mantine-color-gray-7)`
### Dark Shades
- Dark-0: `var(--mantine-color-dark-0)`
- Dark-4: `var(--mantine-color-dark-4)`
- Dark-6: `var(--mantine-color-dark-6)`
- Dark-8: `var(--mantine-color-dark-8)`
## Color Usage By Component
### HeroTitle
- Background: `light-dark(var(--mantine-color-white), var(--mantine-color-dark-8))`
- Text: `light-dark(var(--mantine-color-black), var(--mantine-color-white))`
### Welcome
- Text: `light-dark(var(--mantine-color-black), var(--mantine-color-white))`
### HeaderSimple
- Background: `var(--mantine-color-body)`
- Border: `light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-4))`
- Text: `light-dark(var(--mantine-color-gray-7), var(--mantine-color-dark-0))`
- Menu Background: `light-dark(var(--mantine-color-gray-0), var(--mantine-color-dark-6))`
- Active Item Background: `var(--mantine-color-blue-filled)`
- Active Item Text: `var(--mantine-color-white)`
### ContactIcons
- Icon Color: `var(--mantine-color-white)`
- Icon Hover Color: `var(--mantine-color-blue-0)`
- Text Color: `var(--mantine-color-white)`
### Contact
- Background: `light-dark(var(--mantine-color-white), var(--mantine-color-dark-8))`
### ContactUs
- Gradient: `linear-gradient(to bottom right, var(--mantine-color-blue-4) 0%, var(--mantine-color-blue-7) 100%)`
- Title Color: `var(--mantine-color-white)`
- Subtitle Color: `var(--mantine-color-blue-0)`
- Form Background: `var(--mantine-color-white)`
- Form Button Text: `var(--mantine-color-white)`
- Form Button Hover: `var(--mantine-color-blue-1)`
- Input Background: `var(--mantine-color-white)`
- Input Border: `var(--mantine-color-gray-4)`
- Input Text: `var(--mantine-color-black)`
- Input Placeholder: `var(--mantine-color-gray-5)`
- Submit Button Background: `var(--mantine-color-blue-6)`
## Issues Identified
- Inconsistent use of blue shades across components
- Mix of direct color variables and light-dark functions
- No centralized theme definition with brand colors
- No semantic color naming (e.g., primary, secondary, etc.)
## Next Steps
- Define a comprehensive color palette in theme.ts
- Create semantic color tokens
- Standardize light/dark mode transitions

View File

@@ -0,0 +1,182 @@
# Color System Migration Guide
This guide will help you migrate your components to use our new standardized color system.
## Why Migrate?
- **Consistency**: Ensure all UI elements have consistent colors
- **Maintainability**: Easier to update the design system
- **Accessibility**: Better contrast and readability
- **Dark Mode**: Simplified light/dark mode support
## Migration Steps
### 1. Identify Current Color Usage
First, identify all hardcoded colors or direct Mantine color variables in your component:
```css
/* Before */
.element {
color: #333;
background-color: var(--mantine-color-blue-6);
border: 1px solid var(--mantine-color-gray-3);
}
```
### 2. Replace with Theme Color Tokens
Replace hardcoded colors and direct Mantine variables with our standardized tokens:
```css
/* After */
.element {
color: var(--mantine-color-brand-gray-7);
background-color: var(--mantine-color-brand-primary-6);
border: 1px solid var(--mantine-color-brand-gray-3);
}
```
### 3. Use Semantic Color Tokens Where Available
For common UI elements, use semantic tokens:
```css
/* Before */
.header {
background-color: var(--mantine-color-body);
border-bottom: 1px solid var(--mantine-color-gray-3);
}
/* After */
.header {
background-color: var(--mantine-other-headerBgColor);
border-bottom: 1px solid var(--mantine-other-headerBorderColor);
}
```
### 4. Use Light/Dark Mode Consistently
For elements that need different colors in light/dark mode:
```css
/* Before */
.text {
color: light-dark(var(--mantine-color-gray-7), var(--mantine-color-dark-0));
}
/* After */
.text {
color: light-dark(var(--mantine-color-brand-gray-7), var(--mantine-color-brand-gray-0));
}
```
### 5. Update Inline Styles in Components
For inline styles in components:
```tsx
// Before
<Box style={{ color: theme.colors.blue[6] }} />
// After
<Box style={{ color: 'var(--mantine-color-brand-primary-6)' }} />
// Or better, use Mantine props
<Box c="brand-primary.6" />
```
## Mapping Old Colors to New Colors
Use this reference to map old color values to our new color system:
| Old Color | New Color |
|-----------|-----------|
| `var(--mantine-color-blue-0)` | `var(--mantine-color-brand-primary-0)` |
| `var(--mantine-color-blue-1)` | `var(--mantine-color-brand-primary-1)` |
| `var(--mantine-color-blue-4)` | `var(--mantine-color-brand-primary-4)` |
| `var(--mantine-color-blue-6)` | `var(--mantine-color-brand-primary-6)` |
| `var(--mantine-color-blue-7)` | `var(--mantine-color-brand-primary-7)` |
| `var(--mantine-color-blue-filled)` | `var(--mantine-other-navigationActiveColor)` |
| `var(--mantine-color-gray-0)` | `var(--mantine-color-brand-gray-0)` |
| `var(--mantine-color-gray-3)` | `var(--mantine-color-brand-gray-3)` |
| `var(--mantine-color-gray-4)` | `var(--mantine-color-brand-gray-4)` |
| `var(--mantine-color-gray-5)` | `var(--mantine-color-brand-gray-5)` |
| `var(--mantine-color-gray-7)` | `var(--mantine-color-brand-gray-7)` |
| `var(--mantine-color-dark-0)` | `var(--mantine-color-brand-gray-0)` |
| `var(--mantine-color-dark-4)` | `var(--mantine-color-brand-gray-4)` |
| `var(--mantine-color-dark-6)` | `var(--mantine-color-brand-gray-6)` |
| `var(--mantine-color-dark-8)` | `var(--mantine-color-brand-gray-8)` |
## Examples
### Header Component Example
```css
/* Before */
.header {
background-color: var(--mantine-color-body);
border-bottom: 1px solid light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-4));
}
.link {
color: light-dark(var(--mantine-color-gray-7), var(--mantine-color-dark-0));
}
.link:hover {
background-color: light-dark(var(--mantine-color-gray-0), var(--mantine-color-dark-6));
}
.active {
background-color: var(--mantine-color-blue-filled);
color: var(--mantine-color-white);
}
/* After */
.header {
background-color: var(--mantine-other-headerBgColor);
border-bottom: 1px solid var(--mantine-other-headerBorderColor);
}
.link {
color: light-dark(var(--mantine-color-brand-gray-7), var(--mantine-color-brand-gray-0));
}
.link:hover {
background-color: light-dark(var(--mantine-color-brand-gray-1), var(--mantine-color-brand-gray-8));
}
.active {
background-color: var(--mantine-other-navigationActiveColor);
color: var(--mantine-color-white);
}
```
### Button Component Example
```tsx
// Before
<Button
style={{
backgroundColor: theme.colors.blue[6],
color: 'white'
}}
>
Click me
</Button>
// After
<Button color="brand-primary">Click me</Button>
```
## Testing Your Migration
After migrating, run stylelint to ensure you're not using hardcoded colors:
```bash
yarn stylelint
```
## Need Help?
Refer to the `color-tokens.md` file or the `ColorPalette` component in Storybook for a complete reference of our color system.

View File

@@ -0,0 +1,182 @@
# Color Tokens Documentation
This document provides guidelines for using our standardized color system across the application.
## Color Palette Structure
Each color in our system has 10 shades, numbered from 0 to 9, where:
- 0 is the lightest shade
- 9 is the darkest shade
- 5-6 are the base/primary shades
## Brand Colors
### Brand Primary (Blue)
This is our main brand color, used for primary actions, links, and brand identity elements.
| Token | Hex | Usage |
|-------|-----|-------|
| `var(--mantine-color-brand-primary-0)` | `#EAF4FF` | Background on hover states |
| `var(--mantine-color-brand-primary-1)` | `#D5E9FF` | Background of informational elements |
| `var(--mantine-color-brand-primary-2)` | `#B0D3FF` | Secondary backgrounds |
| `var(--mantine-color-brand-primary-3)` | `#8BBDFF` | Borders, separators |
| `var(--mantine-color-brand-primary-4)` | `#66A7FF` | Hover states for interactive elements |
| `var(--mantine-color-brand-primary-5)` | `#4191FF` | Icons, secondary buttons |
| `var(--mantine-color-brand-primary-6)` | `#1C7BFF` | **Primary buttons, links, focus states** |
| `var(--mantine-color-brand-primary-7)` | `#0065F2` | Active/pressed states |
| `var(--mantine-color-brand-primary-8)` | `#0055CC` | Tertiary text |
| `var(--mantine-color-brand-primary-9)` | `#004099` | Text on light backgrounds |
### Brand Secondary
This complementary color is used for secondary UI elements and visual hierarchy.
| Token | Hex | Usage |
|-------|-----|-------|
| `var(--mantine-color-brand-secondary-0)` | `#F0F4F9` | Alternative background |
| `var(--mantine-color-brand-secondary-1)` | `#E1E9F4` | Secondary hover backgrounds |
| `var(--mantine-color-brand-secondary-2)` | `#C3D4E9` | Disabled backgrounds |
| `var(--mantine-color-brand-secondary-3)` | `#A5BFDE` | Borders, dividers |
| `var(--mantine-color-brand-secondary-4)` | `#87AAD3` | Non-primary icons |
| `var(--mantine-color-brand-secondary-5)` | `#6995C8` | Highlighted text |
| `var(--mantine-color-brand-secondary-6)` | `#4B80BD` | **Secondary buttons, links** |
| `var(--mantine-color-brand-secondary-7)` | `#2D6BB2` | Active/pressed states for secondary elements |
| `var(--mantine-color-brand-secondary-8)` | `#1F5A99` | Secondary text on light backgrounds |
| `var(--mantine-color-brand-secondary-9)` | `#114480` | Dark text on light backgrounds |
### Brand Accent
This color is used for accent elements, call-to-actions, and highlighting important UI elements.
| Token | Hex | Usage |
|-------|-----|-------|
| `var(--mantine-color-brand-accent-0)` | `#FFF0EA` | Highlight backgrounds |
| `var(--mantine-color-brand-accent-1)` | `#FFE1D5` | Notification backgrounds |
| `var(--mantine-color-brand-accent-2)` | `#FFC3AD` | Secondary accent backgrounds |
| `var(--mantine-color-brand-accent-3)` | `#FFA584` | Accent borders |
| `var(--mantine-color-brand-accent-4)` | `#FF875B` | Accent hover states |
| `var(--mantine-color-brand-accent-5)` | `#FF6932` | Secondary CTAs |
| `var(--mantine-color-brand-accent-6)` | `#FF4A09` | **Primary CTAs, important actions** |
| `var(--mantine-color-brand-accent-7)` | `#D93A00` | Active/pressed states for accent elements |
| `var(--mantine-color-brand-accent-8)` | `#B02F00` | Dark accent text on light backgrounds |
| `var(--mantine-color-brand-accent-9)` | `#882400` | Very dark accent, use sparingly |
### Brand Gray
This is our neutral color, used for text, backgrounds, borders, and non-emphasized UI elements.
| Token | Hex | Usage |
|-------|-----|-------|
| `var(--mantine-color-brand-gray-0)` | `#F8F9FA` | Page backgrounds, light mode |
| `var(--mantine-color-brand-gray-1)` | `#F1F3F5` | Card/element backgrounds |
| `var(--mantine-color-brand-gray-2)` | `#E9ECEF` | Alternative backgrounds, hover states |
| `var(--mantine-color-brand-gray-3)` | `#DEE2E6` | **Borders, dividers, separators** |
| `var(--mantine-color-brand-gray-4)` | `#CED4DA` | Disabled elements, secondary borders |
| `var(--mantine-color-brand-gray-5)` | `#ADB5BD` | **Placeholder text, disabled text** |
| `var(--mantine-color-brand-gray-6)` | `#868E96` | **Secondary text** |
| `var(--mantine-color-brand-gray-7)` | `#495057` | **Primary text** |
| `var(--mantine-color-brand-gray-8)` | `#343A40` | Headings, emphasized text |
| `var(--mantine-color-brand-gray-9)` | `#212529` | Extra dark text, header text |
## Semantic Colors
### Success
Used for positive actions, success messages, and confirmations.
| Token | Hex | Usage |
|-------|-----|-------|
| `var(--mantine-color-success-0)` | `#EAFAF1` | Success background |
| `var(--mantine-color-success-1)` | `#D5F5E3` | Light success background |
| `var(--mantine-color-success-2)` | `#ABEBC6` | Secondary success background |
| `var(--mantine-color-success-3)` | `#82E0AA` | Success borders |
| `var(--mantine-color-success-4)` | `#58D68D` | Success hover states |
| `var(--mantine-color-success-5)` | `#2ECC71` | Secondary success elements |
| `var(--mantine-color-success-6)` | `#27AE60` | **Primary success elements, icons** |
| `var(--mantine-color-success-7)` | `#229954` | Active/pressed states |
| `var(--mantine-color-success-8)` | `#1E8449` | Dark success text |
| `var(--mantine-color-success-9)` | `#196F3D` | Very dark success, use sparingly |
### Warning
Used for warnings, alerts that need attention but aren't critical.
| Token | Hex | Usage |
|-------|-----|-------|
| `var(--mantine-color-warning-0)` | `#FEF9E7` | Warning background |
| `var(--mantine-color-warning-1)` | `#FCF3CF` | Light warning background |
| `var(--mantine-color-warning-2)` | `#F9E79F` | Secondary warning background |
| `var(--mantine-color-warning-3)` | `#F7DC6F` | Warning borders |
| `var(--mantine-color-warning-4)` | `#F4D03F` | Warning hover states |
| `var(--mantine-color-warning-5)` | `#F1C40F` | Secondary warning elements |
| `var(--mantine-color-warning-6)` | `#D4AC0D` | **Primary warning elements, icons** |
| `var(--mantine-color-warning-7)` | `#B7950B` | Active/pressed states |
| `var(--mantine-color-warning-8)` | `#9A7D0A` | Dark warning text |
| `var(--mantine-color-warning-9)` | `#7D6608` | Very dark warning, use sparingly |
### Error
Used for errors, destructive actions, and critical alerts.
| Token | Hex | Usage |
|-------|-----|-------|
| `var(--mantine-color-error-0)` | `#FDEDEC` | Error background |
| `var(--mantine-color-error-1)` | `#FADBD8` | Light error background |
| `var(--mantine-color-error-2)` | `#F5B7B1` | Secondary error background |
| `var(--mantine-color-error-3)` | `#F1948A` | Error borders |
| `var(--mantine-color-error-4)` | `#EC7063` | Error hover states |
| `var(--mantine-color-error-5)` | `#E74C3C` | Secondary error elements |
| `var(--mantine-color-error-6)` | `#CB4335` | **Primary error elements, icons** |
| `var(--mantine-color-error-7)` | `#B03A2E` | Active/pressed states |
| `var(--mantine-color-error-8)` | `#943126` | Dark error text |
| `var(--mantine-color-error-9)` | `#78281F` | Very dark error, use sparingly |
## Semantic Tokens
For common UI elements, use these semantic tokens:
| Token | Maps to | Usage |
|-------|--------|-------|
| `var(--mantine-other-headerBgColor)` | `var(--mantine-color-body)` | Header background |
| `var(--mantine-other-headerBorderColor)` | `var(--mantine-color-brand-gray-3)` | Header borders |
| `var(--mantine-other-navigationActiveColor)` | `var(--mantine-color-brand-primary-6)` | Active navigation items |
| `var(--mantine-other-navigationHoverColor)` | `var(--mantine-color-brand-primary-0)` | Hover state for navigation |
| `var(--mantine-other-buttonPrimaryBg)` | `var(--mantine-color-brand-primary-6)` | Primary button background |
| `var(--mantine-other-buttonSecondaryBg)` | `var(--mantine-color-brand-secondary-6)` | Secondary button background |
| `var(--mantine-other-buttonAccentBg)` | `var(--mantine-color-brand-accent-6)` | Accent button background |
## Usage in CSS
### For direct CSS usage
```css
.my-element {
color: var(--mantine-color-brand-primary-6);
background-color: var(--mantine-color-brand-gray-0);
border: 1px solid var(--mantine-color-brand-gray-3);
}
```
### For light/dark mode support
```css
.my-element {
color: light-dark(var(--mantine-color-brand-gray-7), var(--mantine-color-brand-gray-0));
background-color: light-dark(var(--mantine-color-brand-gray-0), var(--mantine-color-brand-gray-8));
}
```
## Usage in Components (with Mantine)
```tsx
import { Button } from '@mantine/core';
// Using theme colors
<Button color="brand-primary">Primary Button</Button>
<Button color="brand-secondary">Secondary Button</Button>
<Button color="brand-accent">Accent Button</Button>
// Using specific shade
<Button color="brand-primary.6">Custom Shade Button</Button>
```

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,16 @@
import type { Meta, StoryObj } from '@storybook/react';
import { ColorPalette } from './ColorPalette';
const meta = {
title: 'Design System/ColorPalette',
component: ColorPalette,
tags: ['autodocs'],
parameters: {
layout: 'padded',
},
} satisfies Meta<typeof ColorPalette>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {};

View File

@@ -0,0 +1,154 @@
import { Box, Group, Stack, Text, Title, useMantineTheme } from '@mantine/core';
interface ColorSwatchProps {
colorName: string;
shade: number;
hex: string;
}
function ColorSwatch({ colorName, shade, hex }: ColorSwatchProps) {
return (
<Box>
<Box
style={{
backgroundColor: hex,
width: '100%',
height: 50,
borderRadius: 5,
marginBottom: 5,
border: '1px solid var(--mantine-color-brand-gray-3)',
}}
/>
<Text size="xs" fw={700}>
{colorName}-{shade}
</Text>
<Text size="xs" c="dimmed">
{hex}
</Text>
</Box>
);
}
interface ColorGroupProps {
title: string;
colorName: string;
description: string;
colors: readonly string[];
}
function ColorGroup({ title, colorName, description, colors }: ColorGroupProps) {
return (
<Stack gap="md">
<Box mb={10}>
<Title order={3}>{title}</Title>
<Text size="sm">{description}</Text>
</Box>
<Group grow>
{colors.map((color, index) => (
<ColorSwatch key={index} colorName={colorName} shade={index} hex={color} />
))}
</Group>
</Stack>
);
}
export function ColorPalette() {
const theme = useMantineTheme();
return (
<Stack gap="xl">
<Title order={1}>Color Palette Documentation</Title>
<Text>
This component showcases all colors defined in our theme system. Use these colors
consistently throughout the application for a cohesive design.
</Text>
<ColorGroup
title="Brand Primary"
colorName="brand-primary"
description="Main brand color for primary actions, links, and brand identity elements."
colors={theme.colors['brand-primary']}
/>
<ColorGroup
title="Brand Secondary"
colorName="brand-secondary"
description="Complementary color for secondary UI elements and visual hierarchy."
colors={theme.colors['brand-secondary']}
/>
<ColorGroup
title="Brand Accent"
colorName="brand-accent"
description="Accent color for call-to-actions and highlighting important elements."
colors={theme.colors['brand-accent']}
/>
<ColorGroup
title="Brand Gray"
colorName="brand-gray"
description="Neutral colors for text, backgrounds, borders, and non-emphasized UI elements."
colors={theme.colors['brand-gray']}
/>
<ColorGroup
title="Success"
colorName="success"
description="Used for positive actions, success messages, and confirmations."
colors={theme.colors.success}
/>
<ColorGroup
title="Warning"
colorName="warning"
description="Used for warnings and alerts that need attention but aren't critical."
colors={theme.colors.warning}
/>
<ColorGroup
title="Error"
colorName="error"
description="Used for errors, destructive actions, and critical alerts."
colors={theme.colors.error}
/>
<Box my={20}>
<Title order={2}>Semantic Color Usage</Title>
<Text mb={10}>These are recommended usages for our color system:</Text>
<Stack gap="xs">
<Text>
<b>Primary Buttons:</b> brand-primary-6
</Text>
<Text>
<b>Secondary Buttons:</b> brand-secondary-6
</Text>
<Text>
<b>Accent Buttons:</b> brand-accent-6
</Text>
<Text>
<b>Text on Light Backgrounds:</b> brand-gray-7
</Text>
<Text>
<b>Text on Dark Backgrounds:</b> brand-gray-0
</Text>
<Text>
<b>Borders & Dividers:</b> brand-gray-3
</Text>
<Text>
<b>Page Backgrounds:</b> brand-gray-0
</Text>
<Text>
<b>Success States:</b> success-6
</Text>
<Text>
<b>Warning States:</b> warning-6
</Text>
<Text>
<b>Error States:</b> error-6
</Text>
</Stack>
</Box>
</Stack>
);
}

View File

@@ -1,12 +1,63 @@
.wrapper {
padding: var(--mantine-spacing-xl);
background-color: light-dark(var(--mantine-color-white), var(--mantine-color-dark-8));
border-radius: var(--mantine-radius-md);
box-shadow: var(--mantine-shadow-lg);
margin-top: 20px;
position: relative;
box-sizing: border-box;
background-color: light-dark(var(--mantine-color-white), var(--mantine-color-dark-8));
}
.inner {
position: relative;
padding-top: 120px;
padding-bottom: 120px;
width: 80%;
}
/* Small screen styles */
@media (max-width: 755px) {
.inner {
padding-bottom: 80px;
padding-top: 80px;
}
}
.title {
font-family:
"Greycliff CF",
var(--mantine-font-family);
font-size: 62px;
font-weight: 900;
line-height: 1.1;
margin: 0;
padding: 0;
color: light-dark(var(--mantine-color-black), var(--mantine-color-white));
}
/* Small screen styles */
@media (max-width: 755px) {
.title {
font-size: 42px;
line-height: 1.2;
}
}
.description {
margin-top: var(--mantine-spacing-xl);
font-size: 24px;
}
/* Small screen styles */
@media (max-width: 755px) {
.description {
font-size: 18px;
}
}
.link {
text-decoration: none;
font-weight: 500;
transition: color 0.2s ease;
}
.link:hover {
text-decoration: underline;
}

View File

@@ -1,25 +1,36 @@
import { Anchor, Container, Stack, Text, Title } from '@mantine/core';
import { Anchor, Container, Text, Stack } from '@mantine/core';
import classes from './Contact.module.css';
export function Contact() {
return (
<Container className={classes.wrapper}>
<Stack gap="md">
<Title className={classes.title}>Get in Touch</Title>
<Text className={classes.description}>
<div className={classes.wrapper}>
<Container fluid size={700} className={classes.inner}>
<h1 className={classes.title}>
<Text component="span" variant="gradient" gradient={{ from: 'blue', to: 'cyan' }} inherit>
Get in Touch
</Text>
</h1>
<Text className={classes.description} c="dimmed">
If you'd like to collaborate, have any questions, or just want to say hello, feel free to
reach out!
</Text>
<Text>
Email: <Anchor href="mailto:cdmacfadyen@proton.me">cdmacfadyen@proton.me</Anchor>
</Text>
<Text>
LinkedIn:{' '}
<Anchor href="https://www.linkedin.com/in/craig-macfadyen-9a2041197" target="_blank">
linkedin.com/in/craigmacfadyen
</Anchor>
</Text>
</Stack>
</Container>
<Stack gap="lg" mt="xl">
<Text size="lg">
Email:{' '}
<Anchor href="mailto:cdmacfadyen@proton.me" className={classes.link}>
cdmacfadyen@proton.me
</Anchor>
</Text>
<Text size="lg">
LinkedIn:{' '}
<Anchor href="https://www.linkedin.com/in/craig-macfadyen-9a2041197" target="_blank" className={classes.link}>
linkedin.com/in/craigmacfadyen
</Anchor>
</Text>
</Stack>
</Container>
</div>
);
}

View File

@@ -1,64 +0,0 @@
.wrapper {
min-height: 400px;
background-image: linear-gradient(
-60deg,
var(--mantine-color-blue-4) 0%,
var(--mantine-color-blue-7) 100%
);
border-radius: var(--mantine-radius-md);
padding: calc(var(--mantine-spacing-xl) * 2.5);
@media (max-width: $mantine-breakpoint-sm) {
padding: calc(var(--mantine-spacing-xl) * 1.5);
}
}
.title {
font-family:
"Greycliff CF",
var(--mantine-font-family);
color: var(--mantine-color-white);
line-height: 1;
}
.description {
color: var(--mantine-color-blue-0);
max-width: 300px;
@media (max-width: $mantine-breakpoint-sm) {
max-width: 100%;
}
}
.form {
background-color: var(--mantine-color-white);
padding: var(--mantine-spacing-xl);
border-radius: var(--mantine-radius-md);
box-shadow: var(--mantine-shadow-lg);
}
.social {
color: var(--mantine-color-white);
@mixin hover {
color: var(--mantine-color-blue-1);
}
}
.input {
background-color: var(--mantine-color-white);
border-color: var(--mantine-color-gray-4);
color: var(--mantine-color-black);
&::placeholder {
color: var(--mantine-color-gray-5);
}
}
.inputLabel {
color: var(--mantine-color-black);
}
.control {
background-color: var(--mantine-color-blue-6);
}

View File

@@ -1,66 +0,0 @@
import { TbBrandInstagram, TbBrandTwitter, TbBrandYoutube } from 'react-icons/tb';
import {
ActionIcon,
Button,
Group,
SimpleGrid,
Text,
Textarea,
TextInput,
Title,
} from '@mantine/core';
import { ContactIconsList } from './ContactIcons';
import classes from './ContactUs.module.css';
const social = [TbBrandInstagram, TbBrandTwitter, TbBrandYoutube];
export function ContactUs() {
const icons = social.map((Icon, index) => (
<ActionIcon key={index} size={28} className={classes.social} variant="transparent">
<Icon size={22} stroke="1.5" />
</ActionIcon>
));
return (
<div className={classes.wrapper}>
<SimpleGrid cols={{ base: 1, sm: 2 }} spacing={50}>
<div>
<Title className={classes.title}>Contact us</Title>
<Text className={classes.description} mt="sm" mb={30}>
Get in touch
</Text>
<ContactIconsList />
<Group mt="xl">{icons}</Group>
</div>
<div className={classes.form}>
<TextInput
label="Email"
placeholder="your@email.com"
required
classNames={{ input: classes.input, label: classes.inputLabel }}
/>
<TextInput
label="Name"
placeholder="John Doe"
mt="md"
classNames={{ input: classes.input, label: classes.inputLabel }}
/>
<Textarea
required
label="Your message"
placeholder="I want to order your goods"
minRows={4}
mt="md"
classNames={{ input: classes.input, label: classes.inputLabel }}
/>
<Group justify="flex-end" mt="md">
<Button className={classes.control}>Send message</Button>
</Group>
</div>
</SimpleGrid>
</div>
);
}

View File

@@ -1,7 +1,7 @@
.header {
height: 56px;
background-color: var(--mantine-color-body);
border-bottom: 1px solid light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-4));
background-color: var(--mantine-other-headerBgColor);
border-bottom: 1px solid var(--mantine-other-headerBorderColor);
}
.inner {
@@ -17,16 +17,16 @@
padding: 8px 12px;
border-radius: var(--mantine-radius-sm);
text-decoration: none;
color: light-dark(var(--mantine-color-gray-7), var(--mantine-color-dark-0));
color: light-dark(var(--mantine-color-brand-gray-7), var(--mantine-color-brand-gray-0));
font-size: var(--mantine-font-size-sm);
font-weight: 500;
@mixin hover {
background-color: light-dark(var(--mantine-color-gray-0), var(--mantine-color-dark-6));
background-color: light-dark(var(--mantine-color-brand-gray-1), var(--mantine-color-brand-gray-8));
}
[data-mantine-color-scheme] &[data-active] {
background-color: var(--mantine-color-blue-filled);
background-color: var(--mantine-other-navigationActiveColor);
color: var(--mantine-color-white);
}
}

View File

@@ -1,42 +1,23 @@
import { useState } from 'react';
import { Burger, Container, Group } from '@mantine/core';
import { Anchor, Burger, Container, Group } 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';
const links = [
{ link: '/about', label: 'Features' },
{ link: '/pricing', label: 'Pricing' },
{ link: '/learn', label: 'Learn' },
{ link: '/community', label: 'Community' },
];
export function HeaderSimple() {
const [opened, { toggle }] = useDisclosure(false);
const [active, setActive] = useState(links[0].link);
const items = links.map((link) => (
<a
key={link.label}
href={link.link}
className={classes.link}
data-active={active === link.link || undefined}
onClick={(event) => {
event.preventDefault();
setActive(link.link);
}}
>
{link.label}
</a>
));
return (
<header className={classes.header}>
<Container size="md" className={classes.inner}>
<MantineLogo size={28} />
<Group gap={5} visibleFrom="xs">
{items}
<Anchor href="#" className={classes.link}>
CV
</Anchor>
<Anchor href="#" className={classes.link}>
Blog
</Anchor>
</Group>
<Burger opened={opened} onClick={toggle} hiddenFrom="xs" size="sm" />

View File

@@ -6,7 +6,7 @@
.inner {
position: relative;
padding-top: 200px;
padding-top: 120px;
padding-bottom: 120px;
width: 80%;
@@ -40,25 +40,4 @@
@media (max-width: $mantine-breakpoint-sm) {
font-size: 18px;
}
}
.controls {
margin-top: calc(var(--mantine-spacing-xl) * 2);
@media (max-width: $mantine-breakpoint-sm) {
margin-top: var(--mantine-spacing-xl);
}
}
.control {
height: 54px;
padding-left: 38px;
padding-right: 38px;
@media (max-width: $mantine-breakpoint-sm) {
height: 54px;
padding-left: 18px;
padding-right: 18px;
flex: 1;
}
}

View File

@@ -1,4 +1,4 @@
import { Button, Container, Group, Text } from '@mantine/core';
import { Container, Text } from '@mantine/core';
// import { GithubIcon } from '@mantinex/dev-icons';
import classes from './HeroTitle.module.css';
@@ -18,28 +18,6 @@ export function HeroTitle() {
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>
<Group className={classes.controls}>
<Button
size="xl"
className={classes.control}
variant="gradient"
gradient={{ from: 'blue', to: 'cyan' }}
>
Get started
</Button>
<Button
component="a"
href="https://github.com/mantinedev/mantine"
size="xl"
variant="default"
className={classes.control}
// leftSection={<GithubIcon size={20} />}
>
GitHub
</Button>
</Group>
</Container>
</div>
);

View File

@@ -1,4 +1,8 @@
.card {
padding-left: 4rem; /* Add more padding to the left */
padding-right: 4rem; /* Add more padding to the right */
}
}
.wrapper {
margin-bottom: 80px;
}

View File

@@ -27,7 +27,7 @@ function TestimonialsCarousel({ testimonials = defaultTestimonials }: Testimonia
const autoplay = Autoplay();
return (
<>
<div className={styles.wrapper}>
<Title ta="center" mb="xl">
Testimonials
</Title>
@@ -62,7 +62,7 @@ function TestimonialsCarousel({ testimonials = defaultTestimonials }: Testimonia
</Carousel.Slide>
))}
</Carousel>
</>
</div>
);
}

View File

@@ -1,5 +1,140 @@
import { createTheme } from '@mantine/core';
import { createTheme, rem } from '@mantine/core';
export const theme = createTheme({
/** Put your mantine theme override here */
/** Color system for the application */
colors: {
// Primary brand color (blue shades from inventory with consistent gradation)
'brand-primary': [
'#EAF4FF', // 0: Lightest shade
'#D5E9FF', // 1
'#B0D3FF', // 2
'#8BBDFF', // 3
'#66A7FF', // 4: Base blue shade
'#4191FF', // 5
'#1C7BFF', // 6
'#0065F2', // 7: Original blue-7 shade
'#0055CC', // 8
'#004099', // 9: Darkest shade
],
// Secondary brand color - a complementary shade to the primary
'brand-secondary': [
'#F0F4F9', // 0
'#E1E9F4', // 1
'#C3D4E9', // 2
'#A5BFDE', // 3
'#87AAD3', // 4
'#6995C8', // 5
'#4B80BD', // 6
'#2D6BB2', // 7
'#1F5A99', // 8
'#114480', // 9
],
// Accent color for highlights, call to actions, important elements
'brand-accent': [
'#FFF0EA', // 0
'#FFE1D5', // 1
'#FFC3AD', // 2
'#FFA584', // 3
'#FF875B', // 4
'#FF6932', // 5
'#FF4A09', // 6
'#D93A00', // 7
'#B02F00', // 8
'#882400', // 9
],
// Standardized gray shades for consistency
'brand-gray': [
'#F8F9FA', // 0
'#F1F3F5', // 1
'#E9ECEF', // 2
'#DEE2E6', // 3
'#CED4DA', // 4
'#ADB5BD', // 5
'#868E96', // 6
'#495057', // 7
'#343A40', // 8
'#212529', // 9
],
// Semantic colors for state indications
success: [
'#EAFAF1', // 0
'#D5F5E3', // 1
'#ABEBC6', // 2
'#82E0AA', // 3
'#58D68D', // 4
'#2ECC71', // 5
'#27AE60', // 6
'#229954', // 7
'#1E8449', // 8
'#196F3D', // 9
],
warning: [
'#FEF9E7', // 0
'#FCF3CF', // 1
'#F9E79F', // 2
'#F7DC6F', // 3
'#F4D03F', // 4
'#F1C40F', // 5
'#D4AC0D', // 6
'#B7950B', // 7
'#9A7D0A', // 8
'#7D6608', // 9
],
error: [
'#FDEDEC', // 0
'#FADBD8', // 1
'#F5B7B1', // 2
'#F1948A', // 3
'#EC7063', // 4
'#E74C3C', // 5
'#CB4335', // 6
'#B03A2E', // 7
'#943126', // 8
'#78281F', // 9
],
},
// Set the primary color to our brand-primary
primaryColor: 'brand-primary',
// Add consistent spacing values
spacing: {
xs: rem(4),
sm: rem(8),
md: rem(16),
lg: rem(24),
xl: rem(32),
'2xl': rem(40),
'3xl': rem(64),
},
// Add consistent border radius values
radius: {
xs: rem(2),
sm: rem(4),
md: rem(8),
lg: rem(16),
xl: rem(24),
},
// Other theme customizations
fontFamily:
'"Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif',
// Add semantic tokens for common elements
other: {
headerBgColor: 'var(--mantine-color-body)',
headerBorderColor: 'var(--mantine-color-brand-gray-3)',
navigationActiveColor: 'var(--mantine-color-brand-primary-6)',
navigationHoverColor: 'var(--mantine-color-brand-primary-0)',
buttonPrimaryBg: 'var(--mantine-color-brand-primary-6)',
buttonSecondaryBg: 'var(--mantine-color-brand-secondary-6)',
buttonAccentBg: 'var(--mantine-color-brand-accent-6)',
},
});